# Loading packages
library(pryr) # Memory usage information
library(lubridate) # date manipulation

Attaching package: ‘lubridate’

The following object is masked from ‘package:base’:

    date
library(dplyr) # data manipulation

Attaching package: ‘dplyr’

The following objects are masked from ‘package:lubridate’:

    intersect, setdiff, union

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
library(tidyr) # data manipulation
library(ggplot2) # graphics
library(plotly) # Interactive graphics

Attaching package: ‘plotly’

The following object is masked from ‘package:ggplot2’:

    last_plot

The following object is masked from ‘package:stats’:

    filter

The following object is masked from ‘package:graphics’:

    layout
library(stringr) # string manipulation
library(stringi) # remove diacritics
library(ggfortify)
library(rjson) # read json
library(nasapower) # nasapower api data
library(ggsci) # Scientific color palletes
library(zoo) # Replace NAs in time series analysis

Attaching package: ‘zoo’

The following objects are masked from ‘package:base’:

    as.Date, as.Date.numeric
library(rgdal) # Work with geo-spatial data
Carregando pacotes exigidos: sp
rgdal: version: 1.4-4, (SVN revision 833)
 Geospatial Data Abstraction Library extensions to R successfully loaded
 Loaded GDAL runtime: GDAL 2.2.3, released 2017/11/20
 Path to GDAL shared files: /usr/share/gdal/2.2
 GDAL binary built with GEOS: TRUE 
 Loaded PROJ.4 runtime: Rel. 4.9.3, 15 August 2016, [PJ_VERSION: 493]
 Path to PROJ.4 shared files: (autodetected)
 Linking to sp version: 1.3-1 
library(sf) # geo-spatial vector data
Linking to GEOS 3.6.2, GDAL 2.2.3, PROJ 4.9.3
library(TSA) # Time Series Analys

Attaching package: ‘TSA’

The following objects are masked from ‘package:stats’:

    acf, arima

The following object is masked from ‘package:utils’:

    tar
library(qwraps2)# for pretty summary statistics

There are 4 csv files containing data about the fires of all ocurrences around all brazilian territory. Each file has data between 1st Sept to 30th Sept of each year from 2015 to 2019.

temp <- list.files(path = "./database/modis_15-19", pattern = "*.csv")
myfiles = lapply(paste0("./database/modis_15-19/", temp), read.csv)

data <- bind_rows(myfiles)

there are 820929 observations in our dataset which sums up to 66.8 MB of storaged data.

str(data)
'data.frame':   885117 obs. of  10 variables:
 $ datahora    : POSIXct, format: "2015-08-11 17:18:00" "2015-08-14 17:48:00" "2015-08-15 16:53:00" ...
 $ estado      : chr  "PARA" "AMAZONAS" "PARA" "PARA" ...
 $ municipio   : chr  "ITAITUBA" "APUI" "ALTAMIRA" "SANTA MARIA DAS BARREIRAS" ...
 $ bioma       : Factor w/ 6 levels "Amazonia","Caatinga",..: 1 1 1 1 3 3 3 3 3 3 ...
 $ diasemchuva : int  NA NA NA NA NA NA NA NA NA NA ...
 $ precipitacao: num  0 0 0 0 0 0 0 0 0 0 ...
 $ riscofogo   : num  0.96 0.95 1 NaN 1 1 1 1 1 1 ...
 $ latitude    : num  -6.51 -7.01 -6.12 -8.67 -6.51 ...
 $ longitude   : num  -56.1 -59.3 -53.4 -50 -44.8 ...
 $ frp         : num  NA NA NA NA NA NA NA NA NA NA ...
summary(data)
   datahora             satelite          pais           estado           municipio        
 Length:885117      AQUA_M-T:885117   Brasil:885117   Length:885117      Length:885117     
 Class :character                                     Class :character   Class :character  
 Mode  :character                                     Mode  :character   Mode  :character  
                                                                                           
                                                                                           
                                                                                           
                                                                                           
            bioma         diasemchuva      precipitacao      riscofogo         latitude      
 Amazonia      :436732   Min.   :  0.0    Min.   :  0.00   Min.   :0.00     Min.   :-33.667  
 Caatinga      : 56296   1st Qu.:  0.0    1st Qu.:  0.00   1st Qu.:0.37     1st Qu.:-12.806  
 Cerrado       :290662   Median :  0.0    Median :  0.00   Median :1.00     Median : -9.244  
 Mata Atlantica: 73284   Mean   :  9.9    Mean   :  1.08   Mean   :0.71     Mean   : -9.954  
 Pampa         :  4985   3rd Qu.:  8.0    3rd Qu.:  0.00   3rd Qu.:1.00     3rd Qu.: -5.826  
 Pantanal      : 23158   Max.   :120.0    Max.   :309.80   Max.   :1.00     Max.   :  5.154  
                         NA's   :401480   NA's   :107875   NA's   :137531                    
   longitude           frp        
 Min.   :-73.67   Min.   :   0.0  
 1st Qu.:-57.03   1st Qu.:  14.7  
 Median :-50.97   Median :  27.3  
 Mean   :-52.15   Mean   :  58.6  
 3rd Qu.:-46.23   3rd Qu.:  56.3  
 Max.   :-34.82   Max.   :7303.4  
                  NA's   :608511  

In order to print a well formatted table of summary statistics, lets write a function to do it

options(qwraps2_markup = "latex")
my_summary <-
  list("diasemchuva" =
       list("min" = ~ min(.data$diasemchuva, na.rm = T),
            "mediana" = ~ qwraps2::median_iqr(.data$diasemchuva, na_rm = T),
            "média (desv. padr.)" = ~ qwraps2::mean_sd(.data$diasemchuva, na_rm = T),
            "máx" = ~ max(.data$diasemchuva, na.rm = T)),
       "precipitacao" =
       list("min" = ~ min(.data$precipitacao, na.rm = T),
            "mediana" = ~ qwraps2::median_iqr(.data$precipitacao, na_rm = T),
            "média (desv. padr.)" = ~ qwraps2::mean_sd(.data$precipitacao, na_rm = T),
            "máx" = ~ max(.data$precipitacao, na.rm = T)),
       "riscofogo" =
       list("min" = ~ min(.data$riscofogo, na.rm = T),
            "mediana" = ~ qwraps2::median_iqr(.data$riscofogo, na_rm = T),
            "média (desv. padr.)" = ~ qwraps2::mean_sd(.data$riscofogo, na_rm = T),
            "máx" = ~ max(.data$riscofogo, na.rm = T)),
       "frp" =
       list("min" = ~ min(.data$frp, na.rm = T),
            "mediana" = ~ qwraps2::median_iqr(.data$frp, na_rm = T),
            "média (desv. padr.)" = ~ qwraps2::mean_sd(.data$frp, na_rm = T),
            "máx" = ~ max(.data$frp, na.rm = T)),
       "Bioma" =
       list("Amazônia" = ~ qwraps2::n_perc0(.data$bioma == 'Amazonia'),
            "Cerrado"  = ~ qwraps2::n_perc0(.data$bioma == 'Cerrado'),
            "Mata Atlântica"  = ~ qwraps2::n_perc0(.data$bioma == 'Mata Atlantica'),
            "Pantanal"  = ~ qwraps2::n_perc0(.data$bioma == 'Pantanal'),
            "Caatinga"  = ~ qwraps2::n_perc0(.data$bioma == 'Caatinga'),
            "Pampa"  = ~ qwraps2::n_perc0(.data$bioma == 'Pampa')
       )
)

### Overall
pretty_summary <- summary_table(data, my_summary)

Aparentemente, A coluna de área industrial e FRP tem poucas entradas não nulas

total_records <- nrow(data)

noWeatherInfo <- is.na(data$diasemchuva)
noFrpInfo <- is.na(data$frp)

paste("Percentage of NAs entries on `FRP` =",
      round(100 * sum(noFrpInfo) / total_records, 2), "%")
[1] "Percentage of NAs entries on `FRP` = 68.75 %"
paste("Percentage of NAs entries on `diasemchuva` =",
      round(100 * (sum(noWeatherInfo)) / total_records, 2), "%")
[1] "Percentage of NAs entries on `diasemchuva` = 45.36 %"

By the last results, it is possible that the number of days with no rain have a huge impact over the fires triggers.

we can also investigate another columns that have either redundant data or not useful data.

levels(data$pais)
[1] "Brasil"
levels(data$satelite)
[1] "AQUA_M-T"
data$pais <- NULL
data$satelite <- NULL

object_size(data)
65 MB

By looking at the structure of our dataframe, it becomes clear that the Datahora is a datetime object not a Factor.

data$datahora <- ymd_hms(str_replace_all(data$datahora,"/","-"))

levels(data$bioma)
[1] "Amazonia"       "Caatinga"       "Cerrado"        "Mata Atlantica" "Pampa"         
[6] "Pantanal"      

We have 6 distincts biomas on our dataset. Perhaps, by knowing how is the distribution of fires among different biomas, we can refine our research.

counts <- table(data$bioma)
counts

      Amazonia       Caatinga        Cerrado Mata Atlantica          Pampa       Pantanal 
        436732          56296         290662          73284           4985          23158 
proportions <- 100*counts / sum(counts)
proportions

      Amazonia       Caatinga        Cerrado Mata Atlantica          Pampa       Pantanal 
    49.3417254      6.3602891     32.8388224      8.2795834      0.5632024      2.6163773 

As we can see, Amazonia represents around half of our dataset. In addition, the number of fire occurrences is very much like the proportion of land that each bioma has in brazilian territory.

————————– Visualisations —————————–

# For text in plots see
# http://r-statistics.co/Complete-Ggplot2-Tutorial-Part2-Customizing-Theme-With-R-Code.html
# For legend in plots see
# https://www.datanovia.com/en/blog/ggplot-legend-title-position-and-labels/

path_ch3 <- "/home/alexandre/Documentos/tcc/images/plots_cap3/"

proportions <- data %>% group_by(bioma) %>% summarise(n = round(100*n()/nrow(.), 1))

quantities <- as.character(sort(desc(proportions$n)))

ggplot(proportions, aes(x = reorder(bioma, -n), y = n, fill = bioma)) + 
    geom_bar(stat = "identity") +
    coord_flip() +
    scale_fill_manual(values = c("#ff5a00", "#999999",  "#ffce00", "#999999", "#999999", "#999999")) +
    labs(title="Proporção de observações por Bioma", y="Proporção %", x="Bioma", caption="Fonte: Elaborado pelo Autor") +
    theme(plot.title=element_text(size=10, 
                                      face="bold", 
                                      family="Arial",
                                      hjust=0.5,
                                      lineheight=1.2),  # title
              plot.subtitle=element_text(size=10, 
                                         family="Arial",
                                         face="bold",
                                         hjust=0.5),  # subtitle
              axis.title.x=element_text(size=8),  # X axis title
              axis.title.y=element_text(size=8),  # Y axis title
              axis.text.x=element_text(size=6,
                                       vjust=.5),  # X axis text
              axis.text.y=element_text(size=6),
              legend.title = element_blank(),
              legend.position = "none",
              plot.caption = element_text(size = 6)) + # Y axis text
              ggsave(paste0(path_ch3, "bioma-proportions.png"), dpi = "retina", width = 10, height = 8, units = "cm")

Now, it is also important to get the underlying trend of the number of fire ocurrences through the months of the year. Let’s start exploring this idea:

data %>% 
  mutate(month = floor_date(date(datahora), "month")) %>% 
  group_by(month, bioma) %>% 
  summarise(n_fires = n()) %>% 
  ggplot(aes(x = month, y = n_fires/1000)) +
  geom_bar(aes(fill = bioma), stat = 'identity') + 
    scale_x_date(date_labels = "%b/%y", date_breaks = "6 months") +
    labs(y = "Number of fires in thousands", title = 'Brazilian Wildfires by Year')

In order to plot the number of fires by state, we must do some data wrangling to put the data in the desired format.


is.odd <- function(x) x %% 2 != 0
is.even <- function(x) x %% 2 == 0

geo_data <- fromJSON(file = "./geo_data/geo_data_states.json")

maps_df <- list()
  for (i in 1:length(geo_data$features)) {
    coordinates <- unlist(geo_data$features[[i]]$geometry$coordinates[[1]])
    long <- coordinates[is.odd(seq_along(coordinates))]
    lat <-  coordinates[is.even(seq_along(coordinates))]
    
    if(length(long) != length(lat)){
      stop("Wrong subset of coordinate vector", call. = FALSE)
    }
    
    geo_length <- length(long)
    
    estado <- toupper(geo_data$features[[i]]$properties$name)
    codigo <- as.integer(geo_data$features[[i]]$properties$codigo_ibg)
    regiao <- as.integer(geo_data$features[[i]]$properties$regiao_id)
    
    maps_df[[i]] <- as_tibble(
      list(
        estado = rep(stri_trans_general(estado,"Latin-ASCII"), geo_length),
        codigo = rep(codigo, geo_length),
        regiao = rep(regiao, geo_length),
        longitude = long,
        latitude = lat
      )
    )
  }
  
  map_df <- bind_rows(maps_df)
# the `estado` column of the map dataframe is a character, so in order
# to avoid coertion from factor to character, let's convert it explicitly
df$estado <- as.character(df$estado)
df %>% 
  select(estado) %>% 
  group_by(estado) %>% 
  summarise(n = n()) %>% 
  right_join(map_df, by = 'estado') %>% 
  ggplot(aes(x = longitude, y = latitude, group = codigo, fill = n/1000)) + 
    geom_polygon() + 
    geom_path(color = 'white', size = 0.1) + 
    scale_fill_continuous(low = "orange", 
                          high = "darkred",
                          name = 'Number of fires\n(thousands)'
                          ) 

As we can see, the state with the most fire ocurrences is Pará in which most of its lands belongs to the amazon ecossystem, this may explain why half the dataset ocurrences comes from Amazon fires.

As we can see below, this trend happens all years.

df %>% 
  select(estado, datahora) %>% 
  mutate(ano = year(datahora)) %>% 
  group_by(estado, ano) %>% 
  summarise(n = n()) %>% 
  right_join(map_df, by = 'estado') %>% 
  ggplot(aes(x = longitude, y = latitude, group = codigo, fill = n/1000)) + 
    geom_polygon() +
    facet_wrap(~ano) +
    geom_path(color = 'white', size = 0.1) + 
    scale_fill_continuous(low = "orange", 
                          high = "darkred",
                          name = 'Number of fires\n(thousands)'
                          ) 

In terms of raw numbers, we can visualize this difference below.

df %>% 
  group_by(estado) %>% 
  ggplot(aes(x = factor(estado))) +
    geom_bar() +
    coord_flip()

Going down one level, let’s try an analysis by county

geo_data_counties <- fromJSON(file = "./geo_data/geo_data_counties.json")

maps_df_counties <- list()
  for (i in 1:length(geo_data_counties$features)) {
    coordinates <- unlist(geo_data_counties$features[[i]]$geometry$coordinates[[1]])
    long <- coordinates[is.odd(seq_along(coordinates))]
    lat <-  coordinates[is.even(seq_along(coordinates))]
    
    if(length(long) != length(lat)){
      stop("Wrong subset of coordinate vector", call. = FALSE)
    }
    
    geo_length <- length(long)
    
    municipio <- geo_data_counties$features[[i]]$properties$name
    municipio <- toupper(stri_trans_general(municipio, "Latin-ASCII"))
    codigo <- as.integer(geo_data_counties$features[[i]]$properties$id)
    
    maps_df_counties[[i]] <- as_tibble(
      list(
        municipio = rep(stri_trans_general(municipio, "Latin-ASCII"), geo_length),
        codigo = rep(codigo, geo_length),
        longitude = long,
        latitude = lat
      )
    )
  }
  
  map_df_county <- bind_rows(maps_df_counties)
df %>% 
  select(municipio) %>% 
  group_by(municipio) %>% 
  summarise(n = n()) %>% 
  right_join(map_df_county, by = 'municipio') %>% 
  ggplot(aes(x = longitude, y = latitude, group = codigo, fill = n)) + 
    geom_polygon() + 
    geom_path(color = 'white', size = 0.1) +
    scale_fill_continuous(low = "orange", 
                          high = "darkred",
                          name = 'Number of fires'
                          ) 

What about that total number of fire ocurrences by state? From when does it come from?

df %>% 
  mutate(ano = year(datahora)) %>% 
  group_by(estado, ano) %>% 
  ggplot(aes(x = factor(estado), fill = factor(ano))) +
    geom_bar() +
    coord_flip()

Let’s repeat the last plot, but now considering the proportions

df %>% 
  mutate(ano = year(datahora)) %>% 
  group_by(estado, ano) %>% 
  ggplot(aes(x = factor(estado), fill = factor(ano))) +
    geom_bar(position = "fill") +
    coord_flip()

Let’s reinforce what we’ve seen by far and plot the data considering a monthly frequency

# Capitalizes names

capitalize <- function(x) {
  s <- strsplit(x, " ")[[1]]
  paste(toupper(substring(s, 1,1)), substring(s, 2),
      sep="", collapse=" ")
}
levels <- c("Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro")

df %>% 
  mutate(mes = factor(sapply(months(datahora), capitalize), levels = levels)) %>%
  group_by(mes) %>%
  ggplot(aes(x = factor(mes), y = 100*..prop.., group = 1)) +
    geom_bar()


df %>% 
  mutate(mes = factor(sapply(months(datahora), capitalize), levels = levels),
         ano = factor(year(datahora))) %>%
  group_by(ano, mes) %>%
  ggplot(aes(x = mes, y = 100*..prop.., group = 1)) +
    geom_bar() + 
    facet_wrap(~ano) + coord_flip()

As we can see, in 2019 the trend was a bit different, maybe it is so because of the popular protests against the liberal and progressive view of brazilian government towards amazonia.

Let’s compact this plot in only one frame:


levels <- c("Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez")

df %>% 
  mutate(mes = factor(sapply(substr(months(df$datahora), 1, 3), capitalize), levels = levels),
         ano = factor(year(datahora))) %>%
  group_by(ano, mes) %>%
  ggplot(aes(x = mes, fill = ano)) +
    geom_bar() + 
    facet_wrap(~ano) +
    coord_flip()


df %>% 
  mutate(mes = factor(sapply(substr(months(df$datahora), 1, 3), capitalize), levels = levels),
         ano = factor(year(datahora))) %>%
  group_by(ano, mes) %>%
  ggplot(aes(x = mes, fill = ano)) +
    geom_bar(position = "dodge")

df %>% 
  mutate(date = date(datahora)) %>% 
  group_by(date) %>% 
  ggplot(aes(x = date, group = 1)) +
   geom_freqpoly(stat = "count") +
   scale_x_date(date_breaks = "6 months", date_labels = "%b/%y")

As we can see above, our data presents strong patterns (seasonality). By doing a Fourier Transform, it is possible get to know what are the main frequencies of this time series.

signal_INPE <- df %>% 
  mutate(date = date(datahora)) %>% 
  group_by(date) %>%
  summarise(n = n())

p <- periodogram(signal_INPE$n)


dd = data.frame(freq=p$freq, spec=p$spec)
order = dd[order(-dd$spec),]
top3 = head(order, 3)

# display the 2 highest "power" frequencies
top3
time <- 1/top3$freq
time
[1] 345.60000 172.80000  90.94737

Therefore, the seasonality of our dataset is given by annualy, semesterly and quaterly periods. For reference, see https://anomaly.io/detect-seasonality-using-fourier-transform-r/index.html and http://www.di.fc.ul.pt/~jpn/r/fourier/fourier.html

Strangely, our dataset only has records of fire occurences from 3 to 6 pm. Why is it?

df %>% 
  mutate(hour = hour(datahora)) %>% 
  group_by(hour) %>% 
  ggplot(aes(x = hour, group = 1)) +
   geom_bar(stat = "count")

O dataframe original não tem informações sobre macro regiões. Utilizando o data frame de mapas, podemos obter esta informação.


regionsList <- list()
codMacroRegions <- list()
n_reg <- length(unique(map_df$regiao))
regions <- unique(map_df$regiao)

for(i in 1:n_reg){
  temp <- map_df %>% filter(regiao == regions[i])
  
  states <- unique(temp$estado)
  regionsList[[i]] <- states
  codMacroRegions[[i]] <- regions[i]
}

names(regionsList) <- c("NORTE", "NORDESTE", "SUDESTE", "CENTRO-OESTE", "SUL")

for(i in 1:n_reg){
  df$macroRegiao[df$estado %in% regionsList[[i]]] <- names(regionsList)[i]
  df$codMacroRegiao[df$estado %in% regionsList[[i]]] <- codMacroRegions[[i]]
}

# O nome regiao do dataframe map_df nao tem o mesmo sentido que no dataframe df
# sendo assim, criou-se um dataframe auxiliar com os nomes correspondentes
temp <- df[,c("macroRegiao", "codMacroRegiao")]
names(temp) <- c("macroregiao", "regiao")

temp %>% 
  group_by(macroregiao, regiao) %>% 
  summarise(n = n()) %>% 
  right_join(map_df, by = 'regiao') %>% 
  ggplot(aes(x = longitude, y = latitude, group = regiao, fill = n/1000)) + 
    geom_polygon() + 
    geom_path(color = 'white', size = 0.1) + 
    scale_fill_continuous(low = "orange", 
                          high = "darkred",
                          name = 'Number of fires\n(thousands)'
                          ) 

na.omit(df) %>% ggplot(aes(x = frp, y = precipitacao, alpha = riscofogo)) +
  geom_point()


na.omit(df) %>% ggplot(aes(x = log(frp), y = precipitacao, alpha = riscofogo)) +
  geom_point()

Notice the relationship among the fire radiative power, the precipitation and the risk of fire. It seems that, with more precipitation, the frp is reduced while with less precipitation the risk of fire remains mostly

na.omit(df) %>% ggplot(aes(x = riscofogo, y = precipitacao, alpha = frp)) +
  geom_point(position = "jitter")

Looking at the distribution of the fire radiative power across different biomas, we can see that it is roughly the same, except for Mata Atlantica and Pampa maybe because Pampa is situated at the south brazil, where temperatures are lower which decreases the chances of fire ocurrences. On the other side, Mata Atlantica is mostly distributed along the coast, implying that the humidity that comes from the ocean may hold fire ocurrences from stroke.

na.omit(df) %>% ggplot(aes(x = bioma, y = log(frp))) +
  geom_boxplot()

# link for reference https://jfly.uni-koeln.de/color/
# The palette with grey:
cbp1 <- c("#D55E00", "#E69F00", "#56B4E9", "#009E73",
          "#F0E442", "#0072B2", "#999999", "#CC79A7")

na.omit(df) %>% ggplot(aes(x = log(frp), col = bioma, fill = bioma)) +
  geom_density(alpha = 0.1) +
  scale_color_manual(values = cbp1) +
  scale_fill_manual(values = cbp1)

As we can see below, we cannot take any conclusion about the risk of fire with respect to the fire radiative power. So sad.

na.omit(df) %>% 
  ggplot(aes(x = riscofogo, y = log(frp), col = bioma)) +
    geom_point() + # Copy from Plot 1
    geom_smooth(method = "lm", se = TRUE) +
    geom_smooth(aes(group = 1), method = "lm", se = TRUE, linetype = 2) 

data19 <- df %>% filter(year(datahora) == '2019')

df %>% 
  select(estado) %>% 
  group_by(estado) %>% 
  summarise(n = n()) %>% 
  right_join(map_df, by = 'estado') %>% 
  ggplot(aes(x = longitude, y = latitude, group = codigo)) + 
    geom_polygon() + 
    geom_point(inherit.aes = F, data = data19, aes(x = longitude, y = latitude, col = bioma), size = 0.1, shape = 3) +
    scale_color_manual(values = cbp1) +
    geom_path(color = 'white', size = 0.1)

What about cumulative sums?

accum_fires_inpe <- df %>%
  mutate(data = date(datahora),
         ano = year(datahora)) %>% 
  select(ano, data) %>% 
  group_by(ano, data) %>% 
  summarise(occurrence = n()) %>% 
  mutate(cum_sum = cumsum(occurrence),
         dia_ano = yday(data))

accum_fires_inpe %>% ggplot(aes(x = data, y = cum_sum)) +
  geom_line() +
  scale_x_date(date_breaks = "4 months", date_labels = "%b/%y")

splitted <- accum_fires_inpe %>% select(ano, dia_ano, cum_sum)

# Using `do` function to replace NAs values with the last records value
tidy <- splitted %>% spread(key = ano, value = cum_sum) %>% do(zoo::na.locf(.))
tidy$`2019`[273:nrow(tidy)] <- NA
tidy <- tidy %>% 
  gather("2015", "2016", "2017", "2018", "2019", key = "year", "value" = fires)
  
tidy %>% 
  ggplot(aes(x = dia_ano, y = fires, col = year)) +
  geom_line() +
  scale_color_manual(values = c("grey", "grey", "grey", "grey", "blue")) +
  scale_x_continuous("Day of the year", breaks = seq(from = 0, to = 366, by = 50)) +
  scale_y_continuous("Number of fires")

———————————————- FIRMS DATA ————————————-

As seen before, our dataset lacks of 70% information about the fire radiative power of fires. In order to analyze this variable with confident outcomes, we need other data sources. From data collected from Nasa Modis project it is possible to enhance the analysis with much more data.

# Load standard science quality data (before 1st aug/19)
nasaModis1 <-  read.csv("./database/DL_FIRE_M6_79475/fire_archive_M6_79475.csv")

# Load NRT  (after 1st aug/19)
nasaModis2 <- read.csv("./database/DL_FIRE_M6_79475/fire_nrt_M6_79475.csv")
str(nasaModis1)
'data.frame':   1454832 obs. of  15 variables:
 $ latitude  : num  -20.2 -20.4 -20.2 -18.1 -20 ...
 $ longitude : num  -40.2 -40.9 -40.2 -42.8 -42 ...
 $ brightness: num  309 305 306 305 302 ...
 $ scan      : num  1.7 1.5 1.7 1.3 1.3 1.7 1.6 1.6 1.1 1.1 ...
 $ track     : num  1.3 1.2 1.3 1.1 1.1 1.3 1.3 1.3 1.1 1.1 ...
 $ acq_date  : Factor w/ 1672 levels "2015-01-01","2015-01-02",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ acq_time  : int  143 143 143 144 144 145 145 145 146 146 ...
 $ satellite : Factor w/ 2 levels "Aqua","Terra": 2 2 2 2 2 2 2 2 2 2 ...
 $ instrument: Factor w/ 1 level "MODIS": 1 1 1 1 1 1 1 1 1 1 ...
 $ confidence: int  50 63 28 63 46 56 42 67 42 77 ...
 $ version   : num  6.2 6.2 6.2 6.2 6.2 6.2 6.2 6.2 6.2 6.2 ...
 $ bright_t31: num  293 289 293 291 288 ...
 $ frp       : num  13.1 13.1 10.3 8.9 7 10.9 9.3 17.2 5 9.7 ...
 $ daynight  : Factor w/ 2 levels "D","N": 2 2 2 2 2 2 2 2 2 2 ...
 $ type      : int  2 0 2 0 0 0 0 0 0 0 ...
str(nasaModis2)
'data.frame':   194052 obs. of  14 variables:
 $ latitude  : num  -22.9 -22.7 -22 -20.8 -20.2 ...
 $ longitude : num  -43.7 -42.7 -42.9 -41.1 -41.8 ...
 $ brightness: num  308 304 303 315 308 ...
 $ scan      : num  1 1 1 1.2 1.1 1.3 1.5 2.1 2.1 1 ...
 $ track     : num  1 1 1 1.1 1 1.1 1.2 1.4 1.4 1 ...
 $ acq_date  : Factor w/ 61 levels "2019-08-01","2019-08-02",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ acq_time  : int  135 135 135 135 135 135 135 135 135 135 ...
 $ satellite : Factor w/ 2 levels "Aqua","Terra": 2 2 2 2 2 2 2 2 2 2 ...
 $ instrument: Factor w/ 1 level "MODIS": 1 1 1 1 1 1 1 1 1 1 ...
 $ confidence: int  75 56 55 90 74 62 46 100 76 88 ...
 $ version   : Factor w/ 1 level "6.0NRT": 1 1 1 1 1 1 1 1 1 1 ...
 $ bright_t31: num  292 288 288 288 289 ...
 $ frp       : num  8.9 7.1 6.8 17.5 10.2 14.9 11.9 62.5 31.6 14 ...
 $ daynight  : Factor w/ 2 levels "D","N": 2 2 2 2 2 2 2 2 2 2 ...

In order to accomplish an accurate analysis in this dataset, we need to filter some rows. By doing so, we can get close to the data quality of INPE’s dataset.

First of all, the type describes the Inferred hot spot type and assumes 4 values: 0 (presumed vegetation fire), 1 (active volcano), 2 (other statis land source), 3 (offshore). Therefore, we’re going the filter the data for type = 0.

Another important thing to note is the confidence variable. This value is based on a collection of intermediate algorithm quantities used in the detection process. It is intended to help users gauge the quality of individual hotspot/fire pixels. Confidence estimates range between 0 and 100% and are assigned one of the three fire classes (low-confidence fire, nominal-confidence fire, or high-confidence fire).

As a consequence, I am going to consider only the records with more than 50% of confidence.

Additionally, notice that the non-standard science quality dataset has no information about the type of the fire. Let’s assume all fires from these bunch are vegetation fires. With this, to bind the two datasets, we need to filter the nasaModis1 to get only type 0 fires and then drop this column since the nasaModis2 does not have this variable.

nasaModis1 <- nasaModis1 %>% filter(type == 0)
nasaModis1$type <- NULL

nasaModis2$version <- as.numeric(nasaModis2$version)

nasaModis <- bind_rows(nasaModis1, nasaModis2)
Unequal factor levels: coercing to characterbinding character and factor vector, coercing into character vectorbinding character and factor vector, coercing into character vector
modis <- nasaModis %>% 
  filter(confidence > 50)

the acq_date variable is of type factor, it needs to be converted to a standard date type;

modis$acq_date <- as.Date(modis$acq_date) 

The filtered data corresponds to 78.3% of the hole dataset. By the summary statistics of the data, we clearly don’t need the columns satellite, instrument, version and type. In addition, the scan and track columns do not provide us with useful information. Hence, they will also be forget.

modis[,c("scan", "track", "satellite", "instrument", "version", "type")] <- NULL

Let’s a plot like the acummulated fires vs day of the year, and also accumulated frp vs day of the year

accum_fires_nasa <- modis %>%
  mutate(acq_year = year(acq_date)) %>% 
  select(acq_year, acq_date) %>% 
  group_by(acq_year, acq_date) %>% 
  summarise(occurrences = n()) %>% 
  mutate(cum_sum = cumsum(occurrences),
         day_year = yday(acq_date))
accum_fires_nasa %>% ggplot(aes(x = acq_date, y = cum_sum)) +
  geom_line() +
  scale_x_date(date_breaks = "4 months", date_labels = "%b/%y")

Wrangling data to plot accumulated fires vs day of the year

splitted <- accum_fires_nasa %>% select(acq_year, day_year, cum_sum)

# Using `do` function to replace NAs values with the last records value
tidy <- splitted %>% spread(key = acq_year, value = cum_sum) %>% do(zoo::na.locf(.))
tidy$`2019`[273:nrow(tidy)] <- NA
tidy <- tidy %>% 
  gather("2015", "2016", "2017", "2018", "2019", key = "acq_year", "value" = fires)
  
tidy %>% 
  ggplot(aes(x = day_year, y = fires / 1000, col = acq_year)) +
  geom_line() +
  scale_color_manual(values = c("grey", "grey", "grey", "grey", "red")) +
  scale_x_continuous("Day of the year", breaks = seq(from = 0, to = 366, by = 50)) +
  scale_y_continuous("Number of fires in thousands")

Now let’s wrap over the frp variable

accum_frp_nasa <- modis %>%
  mutate(acq_year = year(acq_date)) %>% 
  select(acq_year, acq_date, frp) %>% 
  group_by(acq_year, acq_date) %>% 
  summarise(frp = sum(frp)) %>% 
  mutate(cum_frp = cumsum(frp),
         day_year = yday(acq_date))
accum_frp_nasa %>% ggplot(aes(x = acq_date, y = cum_frp/1000000)) +
  geom_line() +
  scale_x_date(date_breaks = "4 months", date_labels = "%b/%y")

splitted <- accum_frp_nasa %>% select(acq_year, day_year, cum_frp)

# Using `do` function to replace NAs values with the last records value
tidy <- splitted %>% spread(key = acq_year, value = cum_frp) %>% do(zoo::na.locf(.))
tidy$`2019`[273:nrow(tidy)] <- NA
tidy <- tidy %>% 
  gather("2015", "2016", "2017", "2018", "2019", key = "acq_year", "value" = frp)
tidy %>% 
  ggplot(aes(x = day_year, y = frp / 1000000, col = acq_year)) +
  geom_line() +
  scale_color_manual(values = c("grey", "grey", "grey", "grey", "red")) +
  scale_x_continuous("Day of the year", breaks = seq(from = 0, to = 366, by = 50)) +
  scale_y_continuous("Fire Radiative power in millions")

The result for MODIS corroborate with those from INPE.

One thing that we do not see until this point was the average fire radiative power along the days of the year. However, as we have many extreme cases, i.e., outliers, we are gonna remove them before plotting the statistics


q1 <- quantile(modis$frp, .25)
q3 <- quantile(modis$frp, .75)
iqr <- IQR(modis$frp)

mild_low <- q1 - 1.5 * iqr
mild_high <- q3 + 1.5 * iqr

clean_modis <- modis[modis$frp > mild_low & modis$frp < mild_high, ] #rows

mean_frp_nasa <- clean_modis %>%
  mutate(acq_year = year(acq_date),
         acq_week = week(acq_date)) %>% 
  select(acq_year, acq_week, frp) %>% 
  group_by(acq_year, acq_week) %>% 
  summarise(mean_frp = mean(frp))
splitted <- mean_frp_nasa %>% select(acq_year, acq_week, mean_frp)

# Using `do` function to replace NAs values with the last records value
tidy <- splitted %>% spread(key = acq_year, value = mean_frp) %>% do(zoo::na.locf(.))
tidy$`2019`[40:nrow(tidy)] <- NA
tidy <- tidy %>% 
  gather("2015", "2016", "2017", "2018", "2019", key = "acq_year", "value" = mean_frp)
tidy %>% 
  ggplot(aes(x = acq_week, y = mean_frp, col = acq_year)) +
  geom_line() +
  scale_color_manual(values = c("grey", "grey", "grey", "grey", "red")) +
  scale_x_continuous("Week of the year", breaks = seq(from = 0, to = 52, by = 4)) +
  scale_y_continuous("Fire Radiative power")

clean_modis %>% 
  group_by(acq_date) %>% 
  summarise(mean_frp = mean(frp)) %>% 
  ggplot(aes(x = acq_date, y = mean_frp)) +
  geom_line() +
  scale_x_date(date_breaks = "4 months", date_labels = "%b/%y")

this graph shows that there 9s a strong seasonality in the mean of the fire radiative power which has strongs components of periods Ts = 360 and Ts = 180 (Ts = sampling period).

Let’s investigate the fires of the Amazonia during the fire season:

Cumulative active fire detections from May 1st through October 1st from MODIS (Aqua + Terra) and VIIRS (SNPP) show that fire detections in 2019 have fallen below cumulative levels of fire activity detected in 2012 (the start of the VIIRS record) and 2017 across the Legal Amazon. Through the end of September, fires in 2019 were more intense than any year since 2012, measured in terms of fire radiative power, consistent with the observed increase in deforestation this year.

shape <- read_sf(dsn = "./geo_data/legal_amazon_simple", layer = "UF_AMLeg_LLwgs84_Simple")

# Shapefile of amazon legal area can also be obtained at http://www.dpi.inpe.br/Ambdata/unidades_administrativas.php

shapeINPE <- read_sf(dsn = "./geo_data/AmLeg_LLwgs84", layer = "amazlegal")
legal_amazon <- as.data.frame(shape$geometry[[1]][[1]])
names(legal_amazon) <- c("longitude", "latitude")

legal_amazon_INPE <- as.data.frame(shapeINPE$geometry[[1]][[1]][[1]])
names(legal_amazon_INPE) <- c("longitude", "latitude")

legal_amazon %>% ggplot(aes(x = longitude, y = latitude)) +
  geom_polygon()


legal_amazon_INPE %>% ggplot(aes(x = longitude, y = latitude)) +
  geom_polygon()


# To see if a point is inside a polygon
# point.in.polygon(-60, -5, shape$geometry[[1]][[1]][,1], shape$geometry[[1]][[1]][,2])
df %>% 
  select(estado) %>% 
  group_by(estado) %>% 
  summarise(n = n()) %>% 
  right_join(map_df, by = 'estado') %>% 
  ggplot(aes(x = longitude, y = latitude, group = codigo)) + 
    geom_polygon() + 
    geom_point(inherit.aes = F, data = data19, aes(x = longitude, y = latitude, col = bioma), size = 0.1, shape = 3) +
    scale_color_manual(values = cbp1) +
    geom_path(color = 'white', size = 0.1) +
  geom_path(inherit.aes = F, data = legal_amazon_INPE, mapping = aes(x = longitude, y = latitude), color = "yellow")

modis_fcount <- read.csv("./database/legal_amazon_fc_frp_20191001/Table_MODIS_fire_counts_2003_2019.csv")
tidy_modis_fcount <- modis_fcount %>% 
  gather(-`DOY`, key = "year", "value" = fires)

tidy_modis_fcount$year <- as.integer(substr(tidy_modis_fcount$year, 2, 5))
tidy_modis_fcount$fires <- as.integer(tidy_modis_fcount$fires)
ggplotly(tidy_modis_fcount %>% 
  ggplot(aes(x = DOY, y = fires, color = factor(year))) +
  geom_line())
modis_avg_frp <- read.csv("./database/legal_amazon_fc_frp_20191001/Table_MODIS_fire_radiative_power_2003_2019.csv")
tidy_modis_avg_frp <- modis_avg_frp %>% 
  gather(-`DOY`, key = "year", "value" = fires)

tidy_modis_avg_frp$year <- as.integer(substr(tidy_modis_avg_frp$year, 2, 5))
tidy_modis_avg_frp$fires <- as.integer(tidy_modis_avg_frp$fires)
ggplotly(
  tidy_modis_avg_frp %>% 
  ggplot(aes(x = DOY, y = fires, color = factor(year))) +
  geom_line()
)

From NasaPower API we can obtain useful data for about 146 weather and climate parameters, such as:

Relative humidty (at two meters) Temperature (at two meters) Precipitation (mm) Maximum/Minimum Monthly Difference From Monthly Averaged All Sky Insolation Wind Speed

geographical data are provided at the resolution of 1/2 arc degree longitude by 1/2 arc degree latitude. for more detailed info go to https://power.larc.nasa.gov/documents/POWER_Data_v9_methodology.pdf

Another useful resource can be found at https://earthobservatory.nasa.gov/images/145464/fires-in-brazil

Also in https://www.globalfiredata.org/data.html we can find data such as carbon emissions and dry matter emissions.

For highly personalizable images go to https://worldview.earthdata.nasa.gov/

Detailed information about fires on the Legal Amazon area is given at http://www.globalfiredata.org/forecast.html#amazonas

Thoughts on fire forecasting https://www.nasa.gov/feature/goddard/2019/fire-forecasting-from-smart-phone-in-wilderness

Wildfires against biodiversity https://onlinelibrary.wiley.com/doi/abs/10.1111/btp.12267 and https://link.springer.com/article/10.1007/s10531-012-0426-8

LS0tCnRpdGxlOiAiV2lsZEZpcmVzIEFuYWx5c2lzIC0gRXhwbG9yYXRvcnkgRGF0YSBBbmFseXNpcyIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0Ci0tLQoKYGBge3Igd2FybmluZz1GQUxTRX0KIyBMb2FkaW5nIHBhY2thZ2VzCmxpYnJhcnkocHJ5cikgIyBNZW1vcnkgdXNhZ2UgaW5mb3JtYXRpb24KbGlicmFyeShsdWJyaWRhdGUpICMgZGF0ZSBtYW5pcHVsYXRpb24KbGlicmFyeShkcGx5cikgIyBkYXRhIG1hbmlwdWxhdGlvbgpsaWJyYXJ5KHRpZHlyKSAjIGRhdGEgbWFuaXB1bGF0aW9uCmxpYnJhcnkoZ2dwbG90MikgIyBncmFwaGljcwpsaWJyYXJ5KHBsb3RseSkgIyBJbnRlcmFjdGl2ZSBncmFwaGljcwpsaWJyYXJ5KHN0cmluZ3IpICMgc3RyaW5nIG1hbmlwdWxhdGlvbgpsaWJyYXJ5KHN0cmluZ2kpICMgcmVtb3ZlIGRpYWNyaXRpY3MKbGlicmFyeShnZ2ZvcnRpZnkpCmxpYnJhcnkocmpzb24pICMgcmVhZCBqc29uCmxpYnJhcnkobmFzYXBvd2VyKSAjIG5hc2Fwb3dlciBhcGkgZGF0YQpsaWJyYXJ5KGdnc2NpKSAjIFNjaWVudGlmaWMgY29sb3IgcGFsbGV0ZXMKbGlicmFyeSh6b28pICMgUmVwbGFjZSBOQXMgaW4gdGltZSBzZXJpZXMgYW5hbHlzaXMKbGlicmFyeShyZ2RhbCkgIyBXb3JrIHdpdGggZ2VvLXNwYXRpYWwgZGF0YQpsaWJyYXJ5KHNmKSAjIGdlby1zcGF0aWFsIHZlY3RvciBkYXRhCmxpYnJhcnkoVFNBKSAjIFRpbWUgU2VyaWVzIEFuYWx5cwpsaWJyYXJ5KHF3cmFwczIpIyBmb3IgcHJldHR5IHN1bW1hcnkgc3RhdGlzdGljcwpgYGAKCgpUaGVyZSBhcmUgNCBjc3YgZmlsZXMgY29udGFpbmluZyBkYXRhIGFib3V0IHRoZSBmaXJlcyBvZiBhbGwgb2N1cnJlbmNlcyBhcm91bmQgYWxsIGJyYXppbGlhbiB0ZXJyaXRvcnkuIEVhY2ggZmlsZSBoYXMgZGF0YSBiZXR3ZWVuIDFzdCBTZXB0IHRvIDMwdGggU2VwdCBvZiBlYWNoIHllYXIgZnJvbSAyMDE1IHRvIDIwMTkuCgpgYGB7cn0KdGVtcCA8LSBsaXN0LmZpbGVzKHBhdGggPSAiLi9kYXRhYmFzZS9tb2Rpc18xNS0xOSIsIHBhdHRlcm4gPSAiKi5jc3YiKQpteWZpbGVzID0gbGFwcGx5KHBhc3RlMCgiLi9kYXRhYmFzZS9tb2Rpc18xNS0xOS8iLCB0ZW1wKSwgcmVhZC5jc3YpCgpkYXRhIDwtIGJpbmRfcm93cyhteWZpbGVzKQpgYGAKCnRoZXJlIGFyZSA4MjA5Mjkgb2JzZXJ2YXRpb25zIGluIG91ciBkYXRhc2V0IHdoaWNoIHN1bXMgdXAgdG8gNjYuOCBNQiBvZiBzdG9yYWdlZCBkYXRhLgoKYGBge3J9CnN0cihkYXRhKQpgYGAKCgpgYGB7cn0Kc3VtbWFyeShkYXRhKQpgYGAKCgpJbiBvcmRlciB0byBwcmludCBhIHdlbGwgZm9ybWF0dGVkIHRhYmxlIG9mIHN1bW1hcnkgc3RhdGlzdGljcywgbGV0cyB3cml0ZSBhIGZ1bmN0aW9uIHRvIGRvIGl0CgpgYGB7cn0Kb3B0aW9ucyhxd3JhcHMyX21hcmt1cCA9ICJsYXRleCIpCm15X3N1bW1hcnkgPC0KICBsaXN0KCJkaWFzZW1jaHV2YSIgPQogICAgICAgbGlzdCgibWluIiA9IH4gbWluKC5kYXRhJGRpYXNlbWNodXZhLCBuYS5ybSA9IFQpLAogICAgICAgICAgICAibWVkaWFuYSIgPSB+IHF3cmFwczI6Om1lZGlhbl9pcXIoLmRhdGEkZGlhc2VtY2h1dmEsIG5hX3JtID0gVCksCiAgICAgICAgICAgICJtw6lkaWEgKGRlc3YuIHBhZHIuKSIgPSB+IHF3cmFwczI6Om1lYW5fc2QoLmRhdGEkZGlhc2VtY2h1dmEsIG5hX3JtID0gVCksCiAgICAgICAgICAgICJtw6F4IiA9IH4gbWF4KC5kYXRhJGRpYXNlbWNodXZhLCBuYS5ybSA9IFQpKSwKICAgICAgICJwcmVjaXBpdGFjYW8iID0KICAgICAgIGxpc3QoIm1pbiIgPSB+IG1pbiguZGF0YSRwcmVjaXBpdGFjYW8sIG5hLnJtID0gVCksCiAgICAgICAgICAgICJtZWRpYW5hIiA9IH4gcXdyYXBzMjo6bWVkaWFuX2lxciguZGF0YSRwcmVjaXBpdGFjYW8sIG5hX3JtID0gVCksCiAgICAgICAgICAgICJtw6lkaWEgKGRlc3YuIHBhZHIuKSIgPSB+IHF3cmFwczI6Om1lYW5fc2QoLmRhdGEkcHJlY2lwaXRhY2FvLCBuYV9ybSA9IFQpLAogICAgICAgICAgICAibcOheCIgPSB+IG1heCguZGF0YSRwcmVjaXBpdGFjYW8sIG5hLnJtID0gVCkpLAogICAgICAgInJpc2NvZm9nbyIgPQogICAgICAgbGlzdCgibWluIiA9IH4gbWluKC5kYXRhJHJpc2NvZm9nbywgbmEucm0gPSBUKSwKICAgICAgICAgICAgIm1lZGlhbmEiID0gfiBxd3JhcHMyOjptZWRpYW5faXFyKC5kYXRhJHJpc2NvZm9nbywgbmFfcm0gPSBUKSwKICAgICAgICAgICAgIm3DqWRpYSAoZGVzdi4gcGFkci4pIiA9IH4gcXdyYXBzMjo6bWVhbl9zZCguZGF0YSRyaXNjb2ZvZ28sIG5hX3JtID0gVCksCiAgICAgICAgICAgICJtw6F4IiA9IH4gbWF4KC5kYXRhJHJpc2NvZm9nbywgbmEucm0gPSBUKSksCiAgICAgICAiZnJwIiA9CiAgICAgICBsaXN0KCJtaW4iID0gfiBtaW4oLmRhdGEkZnJwLCBuYS5ybSA9IFQpLAogICAgICAgICAgICAibWVkaWFuYSIgPSB+IHF3cmFwczI6Om1lZGlhbl9pcXIoLmRhdGEkZnJwLCBuYV9ybSA9IFQpLAogICAgICAgICAgICAibcOpZGlhIChkZXN2LiBwYWRyLikiID0gfiBxd3JhcHMyOjptZWFuX3NkKC5kYXRhJGZycCwgbmFfcm0gPSBUKSwKICAgICAgICAgICAgIm3DoXgiID0gfiBtYXgoLmRhdGEkZnJwLCBuYS5ybSA9IFQpKSwKICAgICAgICJCaW9tYSIgPQogICAgICAgbGlzdCgiQW1hesO0bmlhIiA9IH4gcXdyYXBzMjo6bl9wZXJjMCguZGF0YSRiaW9tYSA9PSAnQW1hem9uaWEnKSwKICAgICAgICAgICAgIkNlcnJhZG8iICA9IH4gcXdyYXBzMjo6bl9wZXJjMCguZGF0YSRiaW9tYSA9PSAnQ2VycmFkbycpLAogICAgICAgICAgICAiTWF0YSBBdGzDom50aWNhIiAgPSB+IHF3cmFwczI6Om5fcGVyYzAoLmRhdGEkYmlvbWEgPT0gJ01hdGEgQXRsYW50aWNhJyksCiAgICAgICAgICAgICJQYW50YW5hbCIgID0gfiBxd3JhcHMyOjpuX3BlcmMwKC5kYXRhJGJpb21hID09ICdQYW50YW5hbCcpLAogICAgICAgICAgICAiQ2FhdGluZ2EiICA9IH4gcXdyYXBzMjo6bl9wZXJjMCguZGF0YSRiaW9tYSA9PSAnQ2FhdGluZ2EnKSwKICAgICAgICAgICAgIlBhbXBhIiAgPSB+IHF3cmFwczI6Om5fcGVyYzAoLmRhdGEkYmlvbWEgPT0gJ1BhbXBhJykKICAgICAgICkKKQoKIyMjIE92ZXJhbGwKcHJldHR5X3N1bW1hcnkgPC0gc3VtbWFyeV90YWJsZShkYXRhLCBteV9zdW1tYXJ5KQoKYGBgCgoKCkFwYXJlbnRlbWVudGUsIEEgY29sdW5hIGRlIMOhcmVhIGluZHVzdHJpYWwgZSBGUlAgdGVtIHBvdWNhcyBlbnRyYWRhcyBuw6NvIG51bGFzCgoKYGBge3J9CnRvdGFsX3JlY29yZHMgPC0gbnJvdyhkYXRhKQoKbm9XZWF0aGVySW5mbyA8LSBpcy5uYShkYXRhJGRpYXNlbWNodXZhKQpub0ZycEluZm8gPC0gaXMubmEoZGF0YSRmcnApCgpwYXN0ZSgiUGVyY2VudGFnZSBvZiBOQXMgZW50cmllcyBvbiBgRlJQYCA9IiwKICAgICAgcm91bmQoMTAwICogc3VtKG5vRnJwSW5mbykgLyB0b3RhbF9yZWNvcmRzLCAyKSwgIiUiKQoKcGFzdGUoIlBlcmNlbnRhZ2Ugb2YgTkFzIGVudHJpZXMgb24gYGRpYXNlbWNodXZhYCA9IiwKICAgICAgcm91bmQoMTAwICogKHN1bShub1dlYXRoZXJJbmZvKSkgLyB0b3RhbF9yZWNvcmRzLCAyKSwgIiUiKQoKYGBgCgpCeSB0aGUgbGFzdCByZXN1bHRzLCBpdCBpcyBwb3NzaWJsZSB0aGF0IHRoZSBudW1iZXIgb2YgZGF5cyB3aXRoIG5vIHJhaW4gaGF2ZSBhIGh1Z2UgaW1wYWN0IG92ZXIgdGhlIGZpcmVzIHRyaWdnZXJzLgoKd2UgY2FuIGFsc28gaW52ZXN0aWdhdGUgYW5vdGhlciBjb2x1bW5zIHRoYXQgaGF2ZSBlaXRoZXIgcmVkdW5kYW50IGRhdGEgb3Igbm90IHVzZWZ1bCBkYXRhLgoKYGBge3J9CmxldmVscyhkYXRhJHBhaXMpCmxldmVscyhkYXRhJHNhdGVsaXRlKQoKZGF0YSRwYWlzIDwtIE5VTEwKZGF0YSRzYXRlbGl0ZSA8LSBOVUxMCgpvYmplY3Rfc2l6ZShkYXRhKQpgYGAKCkJ5IGxvb2tpbmcgYXQgdGhlIHN0cnVjdHVyZSBvZiBvdXIgZGF0YWZyYW1lLCBpdCBiZWNvbWVzIGNsZWFyIHRoYXQgdGhlIGBEYXRhaG9yYWAgaXMgYSBkYXRldGltZSBvYmplY3Qgbm90IGEgRmFjdG9yLgoKYGBge3J9CmRhdGEkZGF0YWhvcmEgPC0geW1kX2htcyhzdHJfcmVwbGFjZV9hbGwoZGF0YSRkYXRhaG9yYSwiLyIsIi0iKSkKCmxldmVscyhkYXRhJGJpb21hKQpgYGAKCldlIGhhdmUgNiBkaXN0aW5jdHMgYmlvbWFzIG9uIG91ciBkYXRhc2V0LiBQZXJoYXBzLCBieSBrbm93aW5nIGhvdyBpcyB0aGUgZGlzdHJpYnV0aW9uIG9mIGZpcmVzIGFtb25nIGRpZmZlcmVudCBiaW9tYXMsIHdlIGNhbiByZWZpbmUgb3VyIHJlc2VhcmNoLgoKYGBge3J9CmNvdW50cyA8LSB0YWJsZShkYXRhJGJpb21hKQpjb3VudHMKCnByb3BvcnRpb25zIDwtIDEwMCpjb3VudHMgLyBzdW0oY291bnRzKQpwcm9wb3J0aW9ucwpgYGAKCkFzIHdlIGNhbiBzZWUsIEFtYXpvbmlhIHJlcHJlc2VudHMgYXJvdW5kIGhhbGYgb2Ygb3VyIGRhdGFzZXQuIEluIGFkZGl0aW9uLCB0aGUgbnVtYmVyIG9mIGZpcmUgb2NjdXJyZW5jZXMgaXMgdmVyeSBtdWNoIGxpa2UgdGhlIHByb3BvcnRpb24gb2YgbGFuZCB0aGF0IGVhY2ggYmlvbWEgaGFzIGluIGJyYXppbGlhbiB0ZXJyaXRvcnkuCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBWaXN1YWxpc2F0aW9ucyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKYGBge3IsIGZpZy53aWR0aCA9IDQsIGZpZy5oZWlnaHQ9IDN9CiMgRm9yIHRleHQgaW4gcGxvdHMgc2VlCiMgaHR0cDovL3Itc3RhdGlzdGljcy5jby9Db21wbGV0ZS1HZ3Bsb3QyLVR1dG9yaWFsLVBhcnQyLUN1c3RvbWl6aW5nLVRoZW1lLVdpdGgtUi1Db2RlLmh0bWwKIyBGb3IgbGVnZW5kIGluIHBsb3RzIHNlZQojIGh0dHBzOi8vd3d3LmRhdGFub3ZpYS5jb20vZW4vYmxvZy9nZ3Bsb3QtbGVnZW5kLXRpdGxlLXBvc2l0aW9uLWFuZC1sYWJlbHMvCgpwYXRoX2NoMyA8LSAiL2hvbWUvYWxleGFuZHJlL0RvY3VtZW50b3MvdGNjL2ltYWdlcy9wbG90c19jYXAzLyIKCnByb3BvcnRpb25zIDwtIGRhdGEgJT4lIGdyb3VwX2J5KGJpb21hKSAlPiUgc3VtbWFyaXNlKG4gPSByb3VuZCgxMDAqbigpL25yb3coLiksIDEpKQoKcXVhbnRpdGllcyA8LSBhcy5jaGFyYWN0ZXIoc29ydChkZXNjKHByb3BvcnRpb25zJG4pKSkKCmdncGxvdChwcm9wb3J0aW9ucywgYWVzKHggPSByZW9yZGVyKGJpb21hLCAtbiksIHkgPSBuLCBmaWxsID0gYmlvbWEpKSArIAogICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICAgIGNvb3JkX2ZsaXAoKSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjZmY1YTAwIiwgIiM5OTk5OTkiLCAgIiNmZmNlMDAiLCAiIzk5OTk5OSIsICIjOTk5OTk5IiwgIiM5OTk5OTkiKSkgKwogICAgbGFicyh0aXRsZT0iUHJvcG9yw6fDo28gZGUgb2JzZXJ2YcOnw7VlcyBwb3IgQmlvbWEiLCB5PSJQcm9wb3LDp8OjbyAlIiwgeD0iQmlvbWEiLCBjYXB0aW9uPSJGb250ZTogRWxhYm9yYWRvIHBlbG8gQXV0b3IiKSArCiAgICB0aGVtZShwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTEwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWNlPSJib2xkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFtaWx5PSJBcmlhbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3Q9MC41LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmVoZWlnaHQ9MS4yKSwgICMgdGl0bGUKICAgICAgICAgICAgICBwbG90LnN1YnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTEwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYW1pbHk9IkFyaWFsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWNlPSJib2xkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoanVzdD0wLjUpLCAgIyBzdWJ0aXRsZQogICAgICAgICAgICAgIGF4aXMudGl0bGUueD1lbGVtZW50X3RleHQoc2l6ZT04KSwgICMgWCBheGlzIHRpdGxlCiAgICAgICAgICAgICAgYXhpcy50aXRsZS55PWVsZW1lbnRfdGV4dChzaXplPTgpLCAgIyBZIGF4aXMgdGl0bGUKICAgICAgICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT02LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2anVzdD0uNSksICAjIFggYXhpcyB0ZXh0CiAgICAgICAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF90ZXh0KHNpemU9NiksCiAgICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICAgICAgICBwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpKSArICMgWSBheGlzIHRleHQKICAgICAgICAgICAgICBnZ3NhdmUocGFzdGUwKHBhdGhfY2gzLCAiYmlvbWEtcHJvcG9ydGlvbnMucG5nIiksIGRwaSA9ICJyZXRpbmEiLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSA4LCB1bml0cyA9ICJjbSIpCgpgYGAKCk5vdywgaXQgaXMgYWxzbyBpbXBvcnRhbnQgdG8gZ2V0IHRoZSB1bmRlcmx5aW5nIHRyZW5kIG9mIHRoZSBudW1iZXIgb2YgZmlyZSBvY3VycmVuY2VzIHRocm91Z2ggdGhlIG1vbnRocyBvZiB0aGUgeWVhci4gTGV0J3Mgc3RhcnQgZXhwbG9yaW5nIHRoaXMgaWRlYToKCmBgYHtyfQpkYXRhICU+JSAKICBtdXRhdGUobW9udGggPSBmbG9vcl9kYXRlKGRhdGUoZGF0YWhvcmEpLCAibW9udGgiKSkgJT4lIAogIGdyb3VwX2J5KG1vbnRoLCBiaW9tYSkgJT4lIAogIHN1bW1hcmlzZShuX2ZpcmVzID0gbigpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gbW9udGgsIHkgPSBuX2ZpcmVzLzEwMDApKSArCiAgZ2VvbV9iYXIoYWVzKGZpbGwgPSBiaW9tYSksIHN0YXQgPSAnaWRlbnRpdHknKSArIAogICAgc2NhbGVfeF9kYXRlKGRhdGVfbGFiZWxzID0gIiViLyV5IiwgZGF0ZV9icmVha3MgPSAiNiBtb250aHMiKSArCiAgICBsYWJzKHkgPSAiTnVtYmVyIG9mIGZpcmVzIGluIHRob3VzYW5kcyIsIHRpdGxlID0gJ0JyYXppbGlhbiBXaWxkZmlyZXMgYnkgWWVhcicpICsKICAgIHRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhY2U9ImJvbGQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYW1pbHk9IkFyaWFsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoanVzdD0wLjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGluZWhlaWdodD0xLjIpLCAgIyB0aXRsZQogICAgICAgICAgICAgIHBsb3Quc3VidGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhbWlseT0iQXJpYWwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhY2U9ImJvbGQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0PTAuNSksICAjIHN1YnRpdGxlCiAgICAgICAgICAgICAgYXhpcy50aXRsZS54PWVsZW1lbnRfdGV4dChzaXplPTgpLCAgIyBYIGF4aXMgdGl0bGUKICAgICAgICAgICAgICBheGlzLnRpdGxlLnk9ZWxlbWVudF90ZXh0KHNpemU9OCksICAjIFkgYXhpcyB0aXRsZQogICAgICAgICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChzaXplPTYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZqdXN0PS41KSwgICMgWCBheGlzIHRleHQKICAgICAgICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgICAgICAgIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChzaXplID0gNikpICsgIyBZIGF4aXMgdGV4dAogICAgICAgICAgICAgIGdnc2F2ZShwYXN0ZTAocGF0aF9jaDMsICJiaW9tYS1wcm9wb3J0aW9ucy5wbmciKSwgZHBpID0gInJldGluYSIsIHdpZHRoID0gMTAsIGhlaWdodCA9IDgsIHVuaXRzID0gImNtIikKYGBgCgpJbiBvcmRlciB0byBwbG90IHRoZSBudW1iZXIgb2YgZmlyZXMgYnkgc3RhdGUsIHdlIG11c3QgZG8gc29tZSBkYXRhIHdyYW5nbGluZyB0byBwdXQgdGhlIGRhdGEgaW4gdGhlIGRlc2lyZWQgZm9ybWF0LgoKYGBge3J9Cgppcy5vZGQgPC0gZnVuY3Rpb24oeCkgeCAlJSAyICE9IDAKaXMuZXZlbiA8LSBmdW5jdGlvbih4KSB4ICUlIDIgPT0gMAoKZ2VvX2RhdGEgPC0gZnJvbUpTT04oZmlsZSA9ICIuL2dlb19kYXRhL2dlb19kYXRhX3N0YXRlcy5qc29uIikKCm1hcHNfZGYgPC0gbGlzdCgpCiAgZm9yIChpIGluIDE6bGVuZ3RoKGdlb19kYXRhJGZlYXR1cmVzKSkgewogICAgY29vcmRpbmF0ZXMgPC0gdW5saXN0KGdlb19kYXRhJGZlYXR1cmVzW1tpXV0kZ2VvbWV0cnkkY29vcmRpbmF0ZXNbWzFdXSkKICAgIGxvbmcgPC0gY29vcmRpbmF0ZXNbaXMub2RkKHNlcV9hbG9uZyhjb29yZGluYXRlcykpXQogICAgbGF0IDwtICBjb29yZGluYXRlc1tpcy5ldmVuKHNlcV9hbG9uZyhjb29yZGluYXRlcykpXQogICAgCiAgICBpZihsZW5ndGgobG9uZykgIT0gbGVuZ3RoKGxhdCkpewogICAgICBzdG9wKCJXcm9uZyBzdWJzZXQgb2YgY29vcmRpbmF0ZSB2ZWN0b3IiLCBjYWxsLiA9IEZBTFNFKQogICAgfQogICAgCiAgICBnZW9fbGVuZ3RoIDwtIGxlbmd0aChsb25nKQogICAgCiAgICBlc3RhZG8gPC0gdG91cHBlcihnZW9fZGF0YSRmZWF0dXJlc1tbaV1dJHByb3BlcnRpZXMkbmFtZSkKICAgIGNvZGlnbyA8LSBhcy5pbnRlZ2VyKGdlb19kYXRhJGZlYXR1cmVzW1tpXV0kcHJvcGVydGllcyRjb2RpZ29faWJnKQogICAgcmVnaWFvIDwtIGFzLmludGVnZXIoZ2VvX2RhdGEkZmVhdHVyZXNbW2ldXSRwcm9wZXJ0aWVzJHJlZ2lhb19pZCkKICAgIAogICAgbWFwc19kZltbaV1dIDwtIGFzX3RpYmJsZSgKICAgICAgbGlzdCgKICAgICAgICBlc3RhZG8gPSByZXAoc3RyaV90cmFuc19nZW5lcmFsKGVzdGFkbywiTGF0aW4tQVNDSUkiKSwgZ2VvX2xlbmd0aCksCiAgICAgICAgY29kaWdvID0gcmVwKGNvZGlnbywgZ2VvX2xlbmd0aCksCiAgICAgICAgcmVnaWFvID0gcmVwKHJlZ2lhbywgZ2VvX2xlbmd0aCksCiAgICAgICAgbG9uZ2l0dWRlID0gbG9uZywKICAgICAgICBsYXRpdHVkZSA9IGxhdAogICAgICApCiAgICApCiAgfQogIAogIG1hcF9kZiA8LSBiaW5kX3Jvd3MobWFwc19kZikKYGBgCgpgYGB7cn0KIyB0aGUgYGVzdGFkb2AgY29sdW1uIG9mIHRoZSBtYXAgZGF0YWZyYW1lIGlzIGEgY2hhcmFjdGVyLCBzbyBpbiBvcmRlcgojIHRvIGF2b2lkIGNvZXJ0aW9uIGZyb20gZmFjdG9yIHRvIGNoYXJhY3RlciwgbGV0J3MgY29udmVydCBpdCBleHBsaWNpdGx5CmRmJGVzdGFkbyA8LSBhcy5jaGFyYWN0ZXIoZGYkZXN0YWRvKQpgYGAKCmBgYHtyfQpkZiAlPiUgCiAgc2VsZWN0KGVzdGFkbykgJT4lIAogIGdyb3VwX2J5KGVzdGFkbykgJT4lIAogIHN1bW1hcmlzZShuID0gbigpKSAlPiUgCiAgcmlnaHRfam9pbihtYXBfZGYsIGJ5ID0gJ2VzdGFkbycpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBsb25naXR1ZGUsIHkgPSBsYXRpdHVkZSwgZ3JvdXAgPSBjb2RpZ28sIGZpbGwgPSBuLzEwMDApKSArIAogICAgZ2VvbV9wb2x5Z29uKCkgKyAKICAgIGdlb21fcGF0aChjb2xvciA9ICd3aGl0ZScsIHNpemUgPSAwLjEpICsgCiAgICBzY2FsZV9maWxsX2NvbnRpbnVvdXMobG93ID0gIm9yYW5nZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGhpZ2ggPSAiZGFya3JlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICdOdW1iZXIgb2YgZmlyZXNcbih0aG91c2FuZHMpJwogICAgICAgICAgICAgICAgICAgICAgICAgICkgCmBgYAoKQXMgd2UgY2FuIHNlZSwgdGhlIHN0YXRlIHdpdGggdGhlIG1vc3QgZmlyZSBvY3VycmVuY2VzIGlzIFBhcsOhIGluIHdoaWNoIG1vc3Qgb2YgaXRzIGxhbmRzIGJlbG9uZ3MgdG8gdGhlIGFtYXpvbiBlY29zc3lzdGVtLCB0aGlzIG1heSBleHBsYWluIHdoeSBoYWxmIHRoZSBkYXRhc2V0IG9jdXJyZW5jZXMgY29tZXMgZnJvbSBBbWF6b24gZmlyZXMuCgpBcyB3ZSBjYW4gc2VlIGJlbG93LCB0aGlzIHRyZW5kIGhhcHBlbnMgYWxsIHllYXJzLgoKYGBge3J9CmRmICU+JSAKICBzZWxlY3QoZXN0YWRvLCBkYXRhaG9yYSkgJT4lIAogIG11dGF0ZShhbm8gPSB5ZWFyKGRhdGFob3JhKSkgJT4lIAogIGdyb3VwX2J5KGVzdGFkbywgYW5vKSAlPiUgCiAgc3VtbWFyaXNlKG4gPSBuKCkpICU+JSAKICByaWdodF9qb2luKG1hcF9kZiwgYnkgPSAnZXN0YWRvJykgJT4lIAogIGdncGxvdChhZXMoeCA9IGxvbmdpdHVkZSwgeSA9IGxhdGl0dWRlLCBncm91cCA9IGNvZGlnbywgZmlsbCA9IG4vMTAwMCkpICsgCiAgICBnZW9tX3BvbHlnb24oKSArCiAgICBmYWNldF93cmFwKH5hbm8pICsKICAgIGdlb21fcGF0aChjb2xvciA9ICd3aGl0ZScsIHNpemUgPSAwLjEpICsgCiAgICBzY2FsZV9maWxsX2NvbnRpbnVvdXMobG93ID0gIm9yYW5nZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGhpZ2ggPSAiZGFya3JlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICdOdW1iZXIgb2YgZmlyZXNcbih0aG91c2FuZHMpJwogICAgICAgICAgICAgICAgICAgICAgICAgICkgCmBgYAoKSW4gdGVybXMgb2YgcmF3IG51bWJlcnMsIHdlIGNhbiB2aXN1YWxpemUgdGhpcyBkaWZmZXJlbmNlIGJlbG93LgoKYGBge3J9CmRmICU+JSAKICBncm91cF9ieShlc3RhZG8pICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBmYWN0b3IoZXN0YWRvKSkpICsKICAgIGdlb21fYmFyKCkgKwogICAgY29vcmRfZmxpcCgpCmBgYAoKR29pbmcgZG93biBvbmUgbGV2ZWwsIGxldCdzIHRyeSBhbiBhbmFseXNpcyBieSBjb3VudHkKCmBgYHtyfQpnZW9fZGF0YV9jb3VudGllcyA8LSBmcm9tSlNPTihmaWxlID0gIi4vZ2VvX2RhdGEvZ2VvX2RhdGFfY291bnRpZXMuanNvbiIpCgptYXBzX2RmX2NvdW50aWVzIDwtIGxpc3QoKQogIGZvciAoaSBpbiAxOmxlbmd0aChnZW9fZGF0YV9jb3VudGllcyRmZWF0dXJlcykpIHsKICAgIGNvb3JkaW5hdGVzIDwtIHVubGlzdChnZW9fZGF0YV9jb3VudGllcyRmZWF0dXJlc1tbaV1dJGdlb21ldHJ5JGNvb3JkaW5hdGVzW1sxXV0pCiAgICBsb25nIDwtIGNvb3JkaW5hdGVzW2lzLm9kZChzZXFfYWxvbmcoY29vcmRpbmF0ZXMpKV0KICAgIGxhdCA8LSAgY29vcmRpbmF0ZXNbaXMuZXZlbihzZXFfYWxvbmcoY29vcmRpbmF0ZXMpKV0KICAgIAogICAgaWYobGVuZ3RoKGxvbmcpICE9IGxlbmd0aChsYXQpKXsKICAgICAgc3RvcCgiV3Jvbmcgc3Vic2V0IG9mIGNvb3JkaW5hdGUgdmVjdG9yIiwgY2FsbC4gPSBGQUxTRSkKICAgIH0KICAgIAogICAgZ2VvX2xlbmd0aCA8LSBsZW5ndGgobG9uZykKICAgIAogICAgbXVuaWNpcGlvIDwtIGdlb19kYXRhX2NvdW50aWVzJGZlYXR1cmVzW1tpXV0kcHJvcGVydGllcyRuYW1lCiAgICBtdW5pY2lwaW8gPC0gdG91cHBlcihzdHJpX3RyYW5zX2dlbmVyYWwobXVuaWNpcGlvLCAiTGF0aW4tQVNDSUkiKSkKICAgIGNvZGlnbyA8LSBhcy5pbnRlZ2VyKGdlb19kYXRhX2NvdW50aWVzJGZlYXR1cmVzW1tpXV0kcHJvcGVydGllcyRpZCkKICAgIAogICAgbWFwc19kZl9jb3VudGllc1tbaV1dIDwtIGFzX3RpYmJsZSgKICAgICAgbGlzdCgKICAgICAgICBtdW5pY2lwaW8gPSByZXAoc3RyaV90cmFuc19nZW5lcmFsKG11bmljaXBpbywgIkxhdGluLUFTQ0lJIiksIGdlb19sZW5ndGgpLAogICAgICAgIGNvZGlnbyA9IHJlcChjb2RpZ28sIGdlb19sZW5ndGgpLAogICAgICAgIGxvbmdpdHVkZSA9IGxvbmcsCiAgICAgICAgbGF0aXR1ZGUgPSBsYXQKICAgICAgKQogICAgKQogIH0KICAKICBtYXBfZGZfY291bnR5IDwtIGJpbmRfcm93cyhtYXBzX2RmX2NvdW50aWVzKQpgYGAKCmBgYHtyfQpkZiAlPiUgCiAgc2VsZWN0KG11bmljaXBpbykgJT4lIAogIGdyb3VwX2J5KG11bmljaXBpbykgJT4lIAogIHN1bW1hcmlzZShuID0gbigpKSAlPiUgCiAgcmlnaHRfam9pbihtYXBfZGZfY291bnR5LCBieSA9ICdtdW5pY2lwaW8nKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gbG9uZ2l0dWRlLCB5ID0gbGF0aXR1ZGUsIGdyb3VwID0gY29kaWdvLCBmaWxsID0gbikpICsgCiAgICBnZW9tX3BvbHlnb24oKSArIAogICAgZ2VvbV9wYXRoKGNvbG9yID0gJ3doaXRlJywgc2l6ZSA9IDAuMSkgKwogICAgc2NhbGVfZmlsbF9jb250aW51b3VzKGxvdyA9ICJvcmFuZ2UiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBoaWdoID0gImRhcmtyZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAnTnVtYmVyIG9mIGZpcmVzJwogICAgICAgICAgICAgICAgICAgICAgICAgICkgCmBgYAoKV2hhdCBhYm91dCB0aGF0IHRvdGFsIG51bWJlciBvZiBmaXJlIG9jdXJyZW5jZXMgYnkgc3RhdGU/IEZyb20gd2hlbiBkb2VzIGl0IGNvbWUgZnJvbT8KCmBgYHtyfQpkZiAlPiUgCiAgbXV0YXRlKGFubyA9IHllYXIoZGF0YWhvcmEpKSAlPiUgCiAgZ3JvdXBfYnkoZXN0YWRvLCBhbm8pICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBmYWN0b3IoZXN0YWRvKSwgZmlsbCA9IGZhY3Rvcihhbm8pKSkgKwogICAgZ2VvbV9iYXIoKSArCiAgICBjb29yZF9mbGlwKCkKYGBgCgpMZXQncyByZXBlYXQgdGhlIGxhc3QgcGxvdCwgYnV0IG5vdyBjb25zaWRlcmluZyB0aGUgcHJvcG9ydGlvbnMKCmBgYHtyfQpkZiAlPiUgCiAgbXV0YXRlKGFubyA9IHllYXIoZGF0YWhvcmEpKSAlPiUgCiAgZ3JvdXBfYnkoZXN0YWRvLCBhbm8pICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBmYWN0b3IoZXN0YWRvKSwgZmlsbCA9IGZhY3Rvcihhbm8pKSkgKwogICAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZmlsbCIpICsKICAgIGNvb3JkX2ZsaXAoKQpgYGAKCkxldCdzIHJlaW5mb3JjZSB3aGF0IHdlJ3ZlIHNlZW4gYnkgZmFyIGFuZCBwbG90IHRoZSBkYXRhIGNvbnNpZGVyaW5nIGEgbW9udGhseSBmcmVxdWVuY3kKCmBgYHtyfQojIENhcGl0YWxpemVzIG5hbWVzCgpjYXBpdGFsaXplIDwtIGZ1bmN0aW9uKHgpIHsKICBzIDwtIHN0cnNwbGl0KHgsICIgIilbWzFdXQogIHBhc3RlKHRvdXBwZXIoc3Vic3RyaW5nKHMsIDEsMSkpLCBzdWJzdHJpbmcocywgMiksCiAgICAgIHNlcD0iIiwgY29sbGFwc2U9IiAiKQp9CmBgYAoKCmBgYHtyfQpsZXZlbHMgPC0gYygiSmFuZWlybyIsICJGZXZlcmVpcm8iLCAiTWFyw6dvIiwgIkFicmlsIiwgIk1haW8iLCAiSnVuaG8iLCAiSnVsaG8iLCAiQWdvc3RvIiwgIlNldGVtYnJvIiwgIk91dHVicm8iLCAiTm92ZW1icm8iLCAiRGV6ZW1icm8iKQoKZGYgJT4lIAogIG11dGF0ZShtZXMgPSBmYWN0b3Ioc2FwcGx5KG1vbnRocyhkYXRhaG9yYSksIGNhcGl0YWxpemUpLCBsZXZlbHMgPSBsZXZlbHMpKSAlPiUKICBncm91cF9ieShtZXMpICU+JQogIGdncGxvdChhZXMoeCA9IGZhY3RvcihtZXMpLCB5ID0gMTAwKi4ucHJvcC4uLCBncm91cCA9IDEpKSArCiAgICBnZW9tX2JhcigpCgpkZiAlPiUgCiAgbXV0YXRlKG1lcyA9IGZhY3RvcihzYXBwbHkobW9udGhzKGRhdGFob3JhKSwgY2FwaXRhbGl6ZSksIGxldmVscyA9IGxldmVscyksCiAgICAgICAgIGFubyA9IGZhY3Rvcih5ZWFyKGRhdGFob3JhKSkpICU+JQogIGdyb3VwX2J5KGFubywgbWVzKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBtZXMsIHkgPSAxMDAqLi5wcm9wLi4sIGdyb3VwID0gMSkpICsKICAgIGdlb21fYmFyKCkgKyAKICAgIGZhY2V0X3dyYXAofmFubykgKyBjb29yZF9mbGlwKCkKYGBgCgpBcyB3ZSBjYW4gc2VlLCBpbiAyMDE5IHRoZSB0cmVuZCB3YXMgYSBiaXQgZGlmZmVyZW50LCBtYXliZSBpdCBpcyBzbyBiZWNhdXNlIG9mIHRoZSBwb3B1bGFyIHByb3Rlc3RzIGFnYWluc3QgdGhlIGxpYmVyYWwgYW5kIHByb2dyZXNzaXZlIHZpZXcgb2YgYnJhemlsaWFuIGdvdmVybm1lbnQgdG93YXJkcyBhbWF6b25pYS4KCkxldCdzIGNvbXBhY3QgdGhpcyBwbG90IGluIG9ubHkgb25lIGZyYW1lOgoKYGBge3J9CgpsZXZlbHMgPC0gYygiSmFuIiwgIkZldiIsICJNYXIiLCAiQWJyIiwgIk1haSIsICJKdW4iLCAiSnVsIiwgIkFnbyIsICJTZXQiLCAiT3V0IiwgIk5vdiIsICJEZXoiKQoKZGYgJT4lIAogIG11dGF0ZShtZXMgPSBmYWN0b3Ioc2FwcGx5KHN1YnN0cihtb250aHMoZGYkZGF0YWhvcmEpLCAxLCAzKSwgY2FwaXRhbGl6ZSksIGxldmVscyA9IGxldmVscyksCiAgICAgICAgIGFubyA9IGZhY3Rvcih5ZWFyKGRhdGFob3JhKSkpICU+JQogIGdyb3VwX2J5KGFubywgbWVzKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBtZXMsIGZpbGwgPSBhbm8pKSArCiAgICBnZW9tX2JhcigpICsgCiAgICBmYWNldF93cmFwKH5hbm8pICsKICAgIGNvb3JkX2ZsaXAoKQoKZGYgJT4lIAogIG11dGF0ZShtZXMgPSBmYWN0b3Ioc2FwcGx5KHN1YnN0cihtb250aHMoZGYkZGF0YWhvcmEpLCAxLCAzKSwgY2FwaXRhbGl6ZSksIGxldmVscyA9IGxldmVscyksCiAgICAgICAgIGFubyA9IGZhY3Rvcih5ZWFyKGRhdGFob3JhKSkpICU+JQogIGdyb3VwX2J5KGFubywgbWVzKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBtZXMsIGZpbGwgPSBhbm8pKSArCiAgICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJkb2RnZSIpCgpgYGAKCmBgYHtyfQpkZiAlPiUgCiAgbXV0YXRlKGRhdGUgPSBkYXRlKGRhdGFob3JhKSkgJT4lIAogIGdyb3VwX2J5KGRhdGUpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBkYXRlLCBncm91cCA9IDEpKSArCiAgIGdlb21fZnJlcXBvbHkoc3RhdCA9ICJjb3VudCIpICsKICAgc2NhbGVfeF9kYXRlKGRhdGVfYnJlYWtzID0gIjYgbW9udGhzIiwgZGF0ZV9sYWJlbHMgPSAiJWIvJXkiKQpgYGAKCkFzIHdlIGNhbiBzZWUgYWJvdmUsIG91ciBkYXRhIHByZXNlbnRzIHN0cm9uZyBwYXR0ZXJucyAoc2Vhc29uYWxpdHkpLiBCeSBkb2luZyBhIEZvdXJpZXIgVHJhbnNmb3JtLCBpdCBpcyBwb3NzaWJsZSBnZXQgdG8ga25vdyB3aGF0IGFyZSB0aGUgbWFpbiBmcmVxdWVuY2llcyBvZiB0aGlzIHRpbWUgc2VyaWVzLgoKYGBge3J9CnNpZ25hbF9JTlBFIDwtIGRmICU+JSAKICBtdXRhdGUoZGF0ZSA9IGRhdGUoZGF0YWhvcmEpKSAlPiUgCiAgZ3JvdXBfYnkoZGF0ZSkgJT4lCiAgc3VtbWFyaXNlKG4gPSBuKCkpCgpwIDwtIHBlcmlvZG9ncmFtKHNpZ25hbF9JTlBFJG4pCgpkZCA9IGRhdGEuZnJhbWUoZnJlcT1wJGZyZXEsIHNwZWM9cCRzcGVjKQpvcmRlciA9IGRkW29yZGVyKC1kZCRzcGVjKSxdCnRvcDMgPSBoZWFkKG9yZGVyLCAzKQoKIyBkaXNwbGF5IHRoZSAyIGhpZ2hlc3QgInBvd2VyIiBmcmVxdWVuY2llcwp0b3AzCmBgYAoKYGBge3J9CnRpbWUgPC0gMS90b3AzJGZyZXEKdGltZQpgYGAKClRoZXJlZm9yZSwgdGhlIHNlYXNvbmFsaXR5IG9mIG91ciBkYXRhc2V0IGlzIGdpdmVuIGJ5IGFubnVhbHksIHNlbWVzdGVybHkgYW5kIHF1YXRlcmx5IHBlcmlvZHMuIEZvciByZWZlcmVuY2UsIHNlZSBodHRwczovL2Fub21hbHkuaW8vZGV0ZWN0LXNlYXNvbmFsaXR5LXVzaW5nLWZvdXJpZXItdHJhbnNmb3JtLXIvaW5kZXguaHRtbCBhbmQgaHR0cDovL3d3dy5kaS5mYy51bC5wdC9+anBuL3IvZm91cmllci9mb3VyaWVyLmh0bWwKClN0cmFuZ2VseSwgb3VyIGRhdGFzZXQgb25seSBoYXMgcmVjb3JkcyBvZiBmaXJlIG9jY3VyZW5jZXMgZnJvbSAzIHRvIDYgcG0uIFdoeSBpcyBpdD8KCmBgYHtyfQpkZiAlPiUgCiAgbXV0YXRlKGhvdXIgPSBob3VyKGRhdGFob3JhKSkgJT4lIAogIGdyb3VwX2J5KGhvdXIpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBob3VyLCBncm91cCA9IDEpKSArCiAgIGdlb21fYmFyKHN0YXQgPSAiY291bnQiKQpgYGAKCk8gZGF0YWZyYW1lIG9yaWdpbmFsIG7Do28gdGVtIGluZm9ybWHDp8O1ZXMgc29icmUgbWFjcm8gcmVnacO1ZXMuIFV0aWxpemFuZG8gbyBkYXRhIGZyYW1lIGRlIG1hcGFzLCBwb2RlbW9zIG9idGVyIGVzdGEgaW5mb3JtYcOnw6NvLgoKYGBge3J9CgpyZWdpb25zTGlzdCA8LSBsaXN0KCkKY29kTWFjcm9SZWdpb25zIDwtIGxpc3QoKQpuX3JlZyA8LSBsZW5ndGgodW5pcXVlKG1hcF9kZiRyZWdpYW8pKQpyZWdpb25zIDwtIHVuaXF1ZShtYXBfZGYkcmVnaWFvKQoKZm9yKGkgaW4gMTpuX3JlZyl7CiAgdGVtcCA8LSBtYXBfZGYgJT4lIGZpbHRlcihyZWdpYW8gPT0gcmVnaW9uc1tpXSkKICAKICBzdGF0ZXMgPC0gdW5pcXVlKHRlbXAkZXN0YWRvKQogIHJlZ2lvbnNMaXN0W1tpXV0gPC0gc3RhdGVzCiAgY29kTWFjcm9SZWdpb25zW1tpXV0gPC0gcmVnaW9uc1tpXQp9CgpuYW1lcyhyZWdpb25zTGlzdCkgPC0gYygiTk9SVEUiLCAiTk9SREVTVEUiLCAiU1VERVNURSIsICJDRU5UUk8tT0VTVEUiLCAiU1VMIikKCmZvcihpIGluIDE6bl9yZWcpewogIGRmJG1hY3JvUmVnaWFvW2RmJGVzdGFkbyAlaW4lIHJlZ2lvbnNMaXN0W1tpXV1dIDwtIG5hbWVzKHJlZ2lvbnNMaXN0KVtpXQogIGRmJGNvZE1hY3JvUmVnaWFvW2RmJGVzdGFkbyAlaW4lIHJlZ2lvbnNMaXN0W1tpXV1dIDwtIGNvZE1hY3JvUmVnaW9uc1tbaV1dCn0KYGBgCgpgYGB7cn0KCiMgTyBub21lIHJlZ2lhbyBkbyBkYXRhZnJhbWUgbWFwX2RmIG5hbyB0ZW0gbyBtZXNtbyBzZW50aWRvIHF1ZSBubyBkYXRhZnJhbWUgZGYKIyBzZW5kbyBhc3NpbSwgY3Jpb3Utc2UgdW0gZGF0YWZyYW1lIGF1eGlsaWFyIGNvbSBvcyBub21lcyBjb3JyZXNwb25kZW50ZXMKdGVtcCA8LSBkZlssYygibWFjcm9SZWdpYW8iLCAiY29kTWFjcm9SZWdpYW8iKV0KbmFtZXModGVtcCkgPC0gYygibWFjcm9yZWdpYW8iLCAicmVnaWFvIikKCnRlbXAgJT4lIAogIGdyb3VwX2J5KG1hY3JvcmVnaWFvLCByZWdpYW8pICU+JSAKICBzdW1tYXJpc2UobiA9IG4oKSkgJT4lIAogIHJpZ2h0X2pvaW4obWFwX2RmLCBieSA9ICdyZWdpYW8nKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gbG9uZ2l0dWRlLCB5ID0gbGF0aXR1ZGUsIGdyb3VwID0gcmVnaWFvLCBmaWxsID0gbi8xMDAwKSkgKyAKICAgIGdlb21fcG9seWdvbigpICsgCiAgICBnZW9tX3BhdGgoY29sb3IgPSAnd2hpdGUnLCBzaXplID0gMC4xKSArIAogICAgc2NhbGVfZmlsbF9jb250aW51b3VzKGxvdyA9ICJvcmFuZ2UiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBoaWdoID0gImRhcmtyZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAnTnVtYmVyIG9mIGZpcmVzXG4odGhvdXNhbmRzKScKICAgICAgICAgICAgICAgICAgICAgICAgICApIApgYGAKCgoKYGBge3J9Cm5hLm9taXQoZGYpICU+JSBnZ3Bsb3QoYWVzKHggPSBmcnAsIHkgPSBwcmVjaXBpdGFjYW8sIGFscGhhID0gcmlzY29mb2dvKSkgKwogIGdlb21fcG9pbnQoKQoKbmEub21pdChkZikgJT4lIGdncGxvdChhZXMoeCA9IGxvZyhmcnApLCB5ID0gcHJlY2lwaXRhY2FvLCBhbHBoYSA9IHJpc2NvZm9nbykpICsKICBnZW9tX3BvaW50KCkKYGBgCgpOb3RpY2UgdGhlIHJlbGF0aW9uc2hpcCBhbW9uZyB0aGUgZmlyZSByYWRpYXRpdmUgcG93ZXIsIHRoZSBwcmVjaXBpdGF0aW9uIGFuZCB0aGUgcmlzayBvZiBmaXJlLiBJdCBzZWVtcyB0aGF0LCB3aXRoIG1vcmUgcHJlY2lwaXRhdGlvbiwgdGhlIGZycCBpcyByZWR1Y2VkIHdoaWxlIHdpdGggbGVzcyBwcmVjaXBpdGF0aW9uIHRoZSByaXNrIG9mIGZpcmUgcmVtYWlucyBtb3N0bHkKCmBgYHtyfQpuYS5vbWl0KGRmKSAlPiUgZ2dwbG90KGFlcyh4ID0gcmlzY29mb2dvLCB5ID0gcHJlY2lwaXRhY2FvLCBhbHBoYSA9IGZycCkpICsKICBnZW9tX3BvaW50KHBvc2l0aW9uID0gImppdHRlciIpCmBgYAoKTG9va2luZyBhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBmaXJlIHJhZGlhdGl2ZSBwb3dlciBhY3Jvc3MgZGlmZmVyZW50IGJpb21hcywgd2UgY2FuIHNlZSB0aGF0IGl0IGlzIHJvdWdobHkgdGhlIHNhbWUsIGV4Y2VwdCBmb3IgTWF0YSBBdGxhbnRpY2EgYW5kIFBhbXBhIG1heWJlIGJlY2F1c2UgUGFtcGEgaXMgc2l0dWF0ZWQgYXQgdGhlIHNvdXRoIGJyYXppbCwgd2hlcmUgdGVtcGVyYXR1cmVzIGFyZSBsb3dlciB3aGljaCBkZWNyZWFzZXMgdGhlIGNoYW5jZXMgb2YgZmlyZSBvY3VycmVuY2VzLiBPbiB0aGUgb3RoZXIgc2lkZSwgTWF0YSBBdGxhbnRpY2EgaXMgbW9zdGx5IGRpc3RyaWJ1dGVkIGFsb25nIHRoZSBjb2FzdCwgaW1wbHlpbmcgdGhhdCB0aGUgaHVtaWRpdHkgdGhhdCBjb21lcyBmcm9tIHRoZSBvY2VhbiBtYXkgaG9sZCBmaXJlIG9jdXJyZW5jZXMgZnJvbSBzdHJva2UuCgpgYGB7cn0KbmEub21pdChkZikgJT4lIGdncGxvdChhZXMoeCA9IGJpb21hLCB5ID0gbG9nKGZycCkpKSArCiAgZ2VvbV9ib3hwbG90KCkKYGBgCgpgYGB7cn0KIyBsaW5rIGZvciByZWZlcmVuY2UgaHR0cHM6Ly9qZmx5LnVuaS1rb2Vsbi5kZS9jb2xvci8KIyBUaGUgcGFsZXR0ZSB3aXRoIGdyZXk6CmNicDEgPC0gYygiI0Q1NUUwMCIsICIjRTY5RjAwIiwgIiM1NkI0RTkiLCAiIzAwOUU3MyIsCiAgICAgICAgICAiI0YwRTQ0MiIsICIjMDA3MkIyIiwgIiM5OTk5OTkiLCAiI0NDNzlBNyIpCgpuYS5vbWl0KGRmKSAlPiUgZ2dwbG90KGFlcyh4ID0gbG9nKGZycCksIGNvbCA9IGJpb21hLCBmaWxsID0gYmlvbWEpKSArCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC4xKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNicDEpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjYnAxKQoKYGBgCgpBcyB3ZSBjYW4gc2VlIGJlbG93LCB3ZSBjYW5ub3QgdGFrZSBhbnkgY29uY2x1c2lvbiBhYm91dCB0aGUgcmlzayBvZiBmaXJlIHdpdGggcmVzcGVjdCB0byB0aGUgZmlyZSByYWRpYXRpdmUgcG93ZXIuIFNvIHNhZC4KCmBgYHtyfQpuYS5vbWl0KGRmKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gcmlzY29mb2dvLCB5ID0gbG9nKGZycCksIGNvbCA9IGJpb21hKSkgKwogICAgZ2VvbV9wb2ludCgpICsgIyBDb3B5IGZyb20gUGxvdCAxCiAgICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IFRSVUUpICsKICAgIGdlb21fc21vb3RoKGFlcyhncm91cCA9IDEpLCBtZXRob2QgPSAibG0iLCBzZSA9IFRSVUUsIGxpbmV0eXBlID0gMikgCmBgYAoKCgpgYGB7cn0KZGF0YTE5IDwtIGRmICU+JSBmaWx0ZXIoeWVhcihkYXRhaG9yYSkgPT0gJzIwMTknKQoKZGYgJT4lIAogIHNlbGVjdChlc3RhZG8pICU+JSAKICBncm91cF9ieShlc3RhZG8pICU+JSAKICBzdW1tYXJpc2UobiA9IG4oKSkgJT4lIAogIHJpZ2h0X2pvaW4obWFwX2RmLCBieSA9ICdlc3RhZG8nKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gbG9uZ2l0dWRlLCB5ID0gbGF0aXR1ZGUsIGdyb3VwID0gY29kaWdvKSkgKyAKICAgIGdlb21fcG9seWdvbigpICsgCiAgICBnZW9tX3BvaW50KGluaGVyaXQuYWVzID0gRiwgZGF0YSA9IGRhdGExOSwgYWVzKHggPSBsb25naXR1ZGUsIHkgPSBsYXRpdHVkZSwgY29sID0gYmlvbWEpLCBzaXplID0gMC4xLCBzaGFwZSA9IDMpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjYnAxKSArCiAgICBnZW9tX3BhdGgoY29sb3IgPSAnd2hpdGUnLCBzaXplID0gMC4xKQpgYGAKCmBgYHtyfQpkYXRhX3llYXJseSA8LSBkZiAlPiUgbXV0YXRlKGFubyA9IHllYXIoZGF0YWhvcmEpKSAlPiUgZ3JvdXBfYnkoZXN0YWRvLCBhbm8pCgpkZiAlPiUKICBzZWxlY3QoZXN0YWRvLCBkYXRhaG9yYSkgJT4lCiAgbXV0YXRlKGFubyA9IHllYXIoZGF0YWhvcmEpKSAlPiUKICBncm91cF9ieShlc3RhZG8sIGFubykgJT4lIAogIHN1bW1hcmlzZShuID0gbigpKSAlPiUgCiAgcmlnaHRfam9pbihtYXBfZGYsIGJ5ID0gJ2VzdGFkbycpICU+JQogIGdncGxvdChhZXMoeCA9IGxvbmdpdHVkZSwgeSA9IGxhdGl0dWRlLCBncm91cCA9IGNvZGlnbykpICsKICAgIGdlb21fcG9seWdvbigpICsKICAgIGdlb21fcG9pbnQoaW5oZXJpdC5hZXMgPSBGLCBkYXRhID0gZGF0YV95ZWFybHksIGFlcyh4ID0gbG9uZ2l0dWRlLCB5ID0gbGF0aXR1ZGUsIGNvbCA9IGJpb21hKSwgc2l6ZSA9IDAuMDUsIHNoYXBlID0gMykgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNicDEpICsKICAgIGZhY2V0X3dyYXAofmFubykgKwogICAgZ2VvbV9wYXRoKGNvbG9yID0gJ3doaXRlJywgc2l6ZSA9IDAuMSkKYGBgCgpXaGF0IGFib3V0IGN1bXVsYXRpdmUgc3Vtcz8KCmBgYHtyfQphY2N1bV9maXJlc19pbnBlIDwtIGRmICU+JQogIG11dGF0ZShkYXRhID0gZGF0ZShkYXRhaG9yYSksCiAgICAgICAgIGFubyA9IHllYXIoZGF0YWhvcmEpKSAlPiUgCiAgc2VsZWN0KGFubywgZGF0YSkgJT4lIAogIGdyb3VwX2J5KGFubywgZGF0YSkgJT4lIAogIHN1bW1hcmlzZShvY2N1cnJlbmNlID0gbigpKSAlPiUgCiAgbXV0YXRlKGN1bV9zdW0gPSBjdW1zdW0ob2NjdXJyZW5jZSksCiAgICAgICAgIGRpYV9hbm8gPSB5ZGF5KGRhdGEpKQoKYWNjdW1fZmlyZXNfaW5wZSAlPiUgZ2dwbG90KGFlcyh4ID0gZGF0YSwgeSA9IGN1bV9zdW0pKSArCiAgZ2VvbV9saW5lKCkgKwogIHNjYWxlX3hfZGF0ZShkYXRlX2JyZWFrcyA9ICI0IG1vbnRocyIsIGRhdGVfbGFiZWxzID0gIiViLyV5IikKYGBgCgpgYGB7cn0Kc3BsaXR0ZWQgPC0gYWNjdW1fZmlyZXNfaW5wZSAlPiUgc2VsZWN0KGFubywgZGlhX2FubywgY3VtX3N1bSkKCiMgVXNpbmcgYGRvYCBmdW5jdGlvbiB0byByZXBsYWNlIE5BcyB2YWx1ZXMgd2l0aCB0aGUgbGFzdCByZWNvcmRzIHZhbHVlCnRpZHkgPC0gc3BsaXR0ZWQgJT4lIHNwcmVhZChrZXkgPSBhbm8sIHZhbHVlID0gY3VtX3N1bSkgJT4lIGRvKHpvbzo6bmEubG9jZiguKSkKdGlkeSRgMjAxOWBbMjczOm5yb3codGlkeSldIDwtIE5BCnRpZHkgPC0gdGlkeSAlPiUgCiAgZ2F0aGVyKCIyMDE1IiwgIjIwMTYiLCAiMjAxNyIsICIyMDE4IiwgIjIwMTkiLCBrZXkgPSAieWVhciIsICJ2YWx1ZSIgPSBmaXJlcykKICAKYGBgCgpgYGB7cn0KdGlkeSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gZGlhX2FubywgeSA9IGZpcmVzLCBjb2wgPSB5ZWFyKSkgKwogIGdlb21fbGluZSgpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiZ3JleSIsICJncmV5IiwgImdyZXkiLCAiZ3JleSIsICJibHVlIikpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoIkRheSBvZiB0aGUgeWVhciIsIGJyZWFrcyA9IHNlcShmcm9tID0gMCwgdG8gPSAzNjYsIGJ5ID0gNTApKSArCiAgc2NhbGVfeV9jb250aW51b3VzKCJOdW1iZXIgb2YgZmlyZXMiKQpgYGAKCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIEZJUk1TIERBVEEgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAgCgoKQXMgc2VlbiBiZWZvcmUsIG91ciBkYXRhc2V0IGxhY2tzIG9mIDcwJSBpbmZvcm1hdGlvbiBhYm91dCB0aGUgZmlyZSByYWRpYXRpdmUgcG93ZXIgb2YgZmlyZXMuIEluIG9yZGVyIHRvIGFuYWx5emUgdGhpcyB2YXJpYWJsZSB3aXRoIGNvbmZpZGVudCBvdXRjb21lcywgd2UgbmVlZCBvdGhlciBkYXRhIHNvdXJjZXMuIEZyb20gZGF0YSBjb2xsZWN0ZWQgZnJvbSBOYXNhIE1vZGlzIHByb2plY3QgaXQgaXMgcG9zc2libGUgdG8gZW5oYW5jZSB0aGUgYW5hbHlzaXMgd2l0aCBtdWNoIG1vcmUgZGF0YS4KCmBgYHtyfQojIEZpbmQgdGhlIGRvY3VtZW50YXRpb24gYXQgaHR0cHM6Ly9lYXJ0aGRhdGEubmFzYS5nb3YvZWFydGgtb2JzZXJ2YXRpb24tZGF0YS9uZWFyLXJlYWwtdGltZS9maXJtcy9hY3RpdmUtZmlyZS1kYXRhCiMgTG9hZCBzdGFuZGFyZCBzY2llbmNlIHF1YWxpdHkgZGF0YSAoYmVmb3JlIDFzdCBhdWcvMTkpCm5hc2FNb2RpczEgPC0gIHJlYWQuY3N2KCIuL2RhdGFiYXNlL0RMX0ZJUkVfTTZfNzk0NzUvZmlyZV9hcmNoaXZlX002Xzc5NDc1LmNzdiIpCgojIExvYWQgTlJUICAoYWZ0ZXIgMXN0IGF1Zy8xOSkKbmFzYU1vZGlzMiA8LSByZWFkLmNzdigiLi9kYXRhYmFzZS9ETF9GSVJFX002Xzc5NDc1L2ZpcmVfbnJ0X002Xzc5NDc1LmNzdiIpCmBgYAoKYGBge3J9CnN0cihuYXNhTW9kaXMxKQpgYGAKCmBgYHtyfQpzdHIobmFzYU1vZGlzMikKYGBgCgpJbiBvcmRlciB0byBhY2NvbXBsaXNoIGFuIGFjY3VyYXRlIGFuYWx5c2lzIGluIHRoaXMgZGF0YXNldCwgd2UgbmVlZCB0byBmaWx0ZXIgc29tZSByb3dzLiBCeSBkb2luZyBzbywgd2UgY2FuIGdldCBjbG9zZSB0byB0aGUgZGF0YSBxdWFsaXR5IG9mIElOUEUncyBkYXRhc2V0LgoKRmlyc3Qgb2YgYWxsLCB0aGUgdHlwZSBkZXNjcmliZXMgdGhlIEluZmVycmVkIGhvdCBzcG90IHR5cGUgYW5kIGFzc3VtZXMgNCB2YWx1ZXM6IDAgKHByZXN1bWVkIHZlZ2V0YXRpb24gZmlyZSksIDEgKGFjdGl2ZSB2b2xjYW5vKSwgMiAob3RoZXIgc3RhdGlzIGxhbmQgc291cmNlKSwgMyAob2Zmc2hvcmUpLiBUaGVyZWZvcmUsIHdlJ3JlIGdvaW5nIHRoZSBmaWx0ZXIgdGhlIGRhdGEgZm9yIHR5cGUgPSAwLgoKQW5vdGhlciBpbXBvcnRhbnQgdGhpbmcgdG8gbm90ZSBpcyB0aGUgY29uZmlkZW5jZSB2YXJpYWJsZS4gVGhpcyB2YWx1ZSBpcyBiYXNlZCBvbiBhIGNvbGxlY3Rpb24gb2YgaW50ZXJtZWRpYXRlIGFsZ29yaXRobSBxdWFudGl0aWVzIHVzZWQgaW4gdGhlIGRldGVjdGlvbiBwcm9jZXNzLiBJdCBpcyBpbnRlbmRlZCB0byBoZWxwIHVzZXJzIGdhdWdlIHRoZSBxdWFsaXR5IG9mIGluZGl2aWR1YWwgaG90c3BvdC9maXJlIHBpeGVscy4gQ29uZmlkZW5jZSBlc3RpbWF0ZXMgcmFuZ2UgYmV0d2VlbiAwIGFuZCAxMDAlIGFuZCBhcmUgYXNzaWduZWQgb25lIG9mIHRoZSB0aHJlZSBmaXJlIGNsYXNzZXMgKGxvdy1jb25maWRlbmNlIGZpcmUsIG5vbWluYWwtY29uZmlkZW5jZSBmaXJlLCBvciBoaWdoLWNvbmZpZGVuY2UgZmlyZSkuCgpBcyBhIGNvbnNlcXVlbmNlLCBJIGFtIGdvaW5nIHRvIGNvbnNpZGVyIG9ubHkgdGhlIHJlY29yZHMgd2l0aCBtb3JlIHRoYW4gNTAlIG9mIGNvbmZpZGVuY2UuIAoKQWRkaXRpb25hbGx5LCBub3RpY2UgdGhhdCB0aGUgbm9uLXN0YW5kYXJkIHNjaWVuY2UgcXVhbGl0eSBkYXRhc2V0IGhhcyBubyBpbmZvcm1hdGlvbiBhYm91dCB0aGUgdHlwZSBvZiB0aGUgZmlyZS4gTGV0J3MgYXNzdW1lIGFsbCBmaXJlcyBmcm9tIHRoZXNlIGJ1bmNoIGFyZSB2ZWdldGF0aW9uIGZpcmVzLiBXaXRoIHRoaXMsIHRvIGJpbmQgdGhlIHR3byBkYXRhc2V0cywgd2UgbmVlZCB0byBmaWx0ZXIgdGhlIG5hc2FNb2RpczEgdG8gZ2V0IG9ubHkgdHlwZSAwIGZpcmVzIGFuZCB0aGVuIGRyb3AgdGhpcyBjb2x1bW4gc2luY2UgdGhlIG5hc2FNb2RpczIgZG9lcyBub3QgaGF2ZSB0aGlzIHZhcmlhYmxlLgoKYGBge3J9Cm5hc2FNb2RpczEgPC0gbmFzYU1vZGlzMSAlPiUgZmlsdGVyKHR5cGUgPT0gMCkKbmFzYU1vZGlzMSR0eXBlIDwtIE5VTEwKCm5hc2FNb2RpczIkdmVyc2lvbiA8LSBhcy5udW1lcmljKG5hc2FNb2RpczIkdmVyc2lvbikKCm5hc2FNb2RpcyA8LSBiaW5kX3Jvd3MobmFzYU1vZGlzMSwgbmFzYU1vZGlzMikKCm1vZGlzIDwtIG5hc2FNb2RpcyAlPiUgCiAgZmlsdGVyKGNvbmZpZGVuY2UgPiA1MCkKYGBgCgp0aGUgYWNxX2RhdGUgdmFyaWFibGUgaXMgb2YgdHlwZSBmYWN0b3IsIGl0IG5lZWRzIHRvIGJlIGNvbnZlcnRlZCB0byBhIHN0YW5kYXJkIGRhdGUgdHlwZTsKCmBgYHtyfQptb2RpcyRhY3FfZGF0ZSA8LSBhcy5EYXRlKG1vZGlzJGFjcV9kYXRlKSAKYGBgCgoKVGhlIGZpbHRlcmVkIGRhdGEgY29ycmVzcG9uZHMgdG8gNzguMyUgb2YgdGhlIGhvbGUgZGF0YXNldC4gQnkgdGhlIHN1bW1hcnkgc3RhdGlzdGljcyBvZiB0aGUgZGF0YSwgd2UgY2xlYXJseSBkb24ndCBuZWVkIHRoZSBjb2x1bW5zIHNhdGVsbGl0ZSwgaW5zdHJ1bWVudCwgdmVyc2lvbiBhbmQgdHlwZS4gSW4gYWRkaXRpb24sIHRoZSBzY2FuIGFuZCB0cmFjayBjb2x1bW5zIGRvIG5vdCBwcm92aWRlIHVzIHdpdGggdXNlZnVsIGluZm9ybWF0aW9uLiBIZW5jZSwgdGhleSB3aWxsIGFsc28gYmUgZm9yZ2V0LgoKYGBge3J9Cm1vZGlzWyxjKCJzY2FuIiwgInRyYWNrIiwgInNhdGVsbGl0ZSIsICJpbnN0cnVtZW50IiwgInZlcnNpb24iLCAidHlwZSIpXSA8LSBOVUxMCmBgYAoKTGV0J3MgYSBwbG90IGxpa2UgdGhlIGFjdW1tdWxhdGVkIGZpcmVzIHZzIGRheSBvZiB0aGUgeWVhciwgYW5kIGFsc28gYWNjdW11bGF0ZWQgZnJwIHZzIGRheSBvZiB0aGUgeWVhcgoKYGBge3J9CmFjY3VtX2ZpcmVzX25hc2EgPC0gbW9kaXMgJT4lCiAgbXV0YXRlKGFjcV95ZWFyID0geWVhcihhY3FfZGF0ZSkpICU+JSAKICBzZWxlY3QoYWNxX3llYXIsIGFjcV9kYXRlKSAlPiUgCiAgZ3JvdXBfYnkoYWNxX3llYXIsIGFjcV9kYXRlKSAlPiUgCiAgc3VtbWFyaXNlKG9jY3VycmVuY2VzID0gbigpKSAlPiUgCiAgbXV0YXRlKGN1bV9zdW0gPSBjdW1zdW0ob2NjdXJyZW5jZXMpLAogICAgICAgICBkYXlfeWVhciA9IHlkYXkoYWNxX2RhdGUpKQpgYGAKCmBgYHtyfQphY2N1bV9maXJlc19uYXNhICU+JSBnZ3Bsb3QoYWVzKHggPSBhY3FfZGF0ZSwgeSA9IGN1bV9zdW0pKSArCiAgZ2VvbV9saW5lKCkgKwogIHNjYWxlX3hfZGF0ZShkYXRlX2JyZWFrcyA9ICI0IG1vbnRocyIsIGRhdGVfbGFiZWxzID0gIiViLyV5IikKYGBgCgpXcmFuZ2xpbmcgZGF0YSB0byBwbG90IGFjY3VtdWxhdGVkIGZpcmVzIHZzIGRheSBvZiB0aGUgeWVhcgoKYGBge3J9CnNwbGl0dGVkIDwtIGFjY3VtX2ZpcmVzX25hc2EgJT4lIHNlbGVjdChhY3FfeWVhciwgZGF5X3llYXIsIGN1bV9zdW0pCgojIFVzaW5nIGBkb2AgZnVuY3Rpb24gdG8gcmVwbGFjZSBOQXMgdmFsdWVzIHdpdGggdGhlIGxhc3QgcmVjb3JkcyB2YWx1ZQp0aWR5IDwtIHNwbGl0dGVkICU+JSBzcHJlYWQoa2V5ID0gYWNxX3llYXIsIHZhbHVlID0gY3VtX3N1bSkgJT4lIGRvKHpvbzo6bmEubG9jZiguKSkKdGlkeSRgMjAxOWBbMjczOm5yb3codGlkeSldIDwtIE5BCnRpZHkgPC0gdGlkeSAlPiUgCiAgZ2F0aGVyKCIyMDE1IiwgIjIwMTYiLCAiMjAxNyIsICIyMDE4IiwgIjIwMTkiLCBrZXkgPSAiYWNxX3llYXIiLCAidmFsdWUiID0gZmlyZXMpCiAgCmBgYAoKCmBgYHtyfQp0aWR5ICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBkYXlfeWVhciwgeSA9IGZpcmVzIC8gMTAwMCwgY29sID0gYWNxX3llYXIpKSArCiAgZ2VvbV9saW5lKCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJncmV5IiwgImdyZXkiLCAiZ3JleSIsICJncmV5IiwgInJlZCIpKSArCiAgc2NhbGVfeF9jb250aW51b3VzKCJEYXkgb2YgdGhlIHllYXIiLCBicmVha3MgPSBzZXEoZnJvbSA9IDAsIHRvID0gMzY2LCBieSA9IDUwKSkgKwogIHNjYWxlX3lfY29udGludW91cygiTnVtYmVyIG9mIGZpcmVzIGluIHRob3VzYW5kcyIpCmBgYAoKTm93IGxldCdzIHdyYXAgb3ZlciB0aGUgZnJwIHZhcmlhYmxlCgpgYGB7cn0KYWNjdW1fZnJwX25hc2EgPC0gbW9kaXMgJT4lCiAgbXV0YXRlKGFjcV95ZWFyID0geWVhcihhY3FfZGF0ZSkpICU+JSAKICBzZWxlY3QoYWNxX3llYXIsIGFjcV9kYXRlLCBmcnApICU+JSAKICBncm91cF9ieShhY3FfeWVhciwgYWNxX2RhdGUpICU+JSAKICBzdW1tYXJpc2UoZnJwID0gc3VtKGZycCkpICU+JSAKICBtdXRhdGUoY3VtX2ZycCA9IGN1bXN1bShmcnApLAogICAgICAgICBkYXlfeWVhciA9IHlkYXkoYWNxX2RhdGUpKQpgYGAKCmBgYHtyfQphY2N1bV9mcnBfbmFzYSAlPiUgZ2dwbG90KGFlcyh4ID0gYWNxX2RhdGUsIHkgPSBjdW1fZnJwLzEwMDAwMDApKSArCiAgZ2VvbV9saW5lKCkgKwogIHNjYWxlX3hfZGF0ZShkYXRlX2JyZWFrcyA9ICI0IG1vbnRocyIsIGRhdGVfbGFiZWxzID0gIiViLyV5IikKYGBgCgpgYGB7cn0Kc3BsaXR0ZWQgPC0gYWNjdW1fZnJwX25hc2EgJT4lIHNlbGVjdChhY3FfeWVhciwgZGF5X3llYXIsIGN1bV9mcnApCgojIFVzaW5nIGBkb2AgZnVuY3Rpb24gdG8gcmVwbGFjZSBOQXMgdmFsdWVzIHdpdGggdGhlIGxhc3QgcmVjb3JkcyB2YWx1ZQp0aWR5IDwtIHNwbGl0dGVkICU+JSBzcHJlYWQoa2V5ID0gYWNxX3llYXIsIHZhbHVlID0gY3VtX2ZycCkgJT4lIGRvKHpvbzo6bmEubG9jZiguKSkKdGlkeSRgMjAxOWBbMjczOm5yb3codGlkeSldIDwtIE5BCnRpZHkgPC0gdGlkeSAlPiUgCiAgZ2F0aGVyKCIyMDE1IiwgIjIwMTYiLCAiMjAxNyIsICIyMDE4IiwgIjIwMTkiLCBrZXkgPSAiYWNxX3llYXIiLCAidmFsdWUiID0gZnJwKQpgYGAKCmBgYHtyfQp0aWR5ICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBkYXlfeWVhciwgeSA9IGZycCAvIDEwMDAwMDAsIGNvbCA9IGFjcV95ZWFyKSkgKwogIGdlb21fbGluZSgpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiZ3JleSIsICJncmV5IiwgImdyZXkiLCAiZ3JleSIsICJyZWQiKSkgKwogIHNjYWxlX3hfY29udGludW91cygiRGF5IG9mIHRoZSB5ZWFyIiwgYnJlYWtzID0gc2VxKGZyb20gPSAwLCB0byA9IDM2NiwgYnkgPSA1MCkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoIkZpcmUgUmFkaWF0aXZlIHBvd2VyIGluIG1pbGxpb25zIikKYGBgCgpUaGUgcmVzdWx0IGZvciBNT0RJUyBjb3Jyb2JvcmF0ZSB3aXRoIHRob3NlIGZyb20gSU5QRS4KCk9uZSB0aGluZyB0aGF0IHdlIGRvIG5vdCBzZWUgdW50aWwgdGhpcyBwb2ludCB3YXMgdGhlIGF2ZXJhZ2UgZmlyZSByYWRpYXRpdmUgcG93ZXIgYWxvbmcgdGhlIGRheXMgb2YgdGhlIHllYXIuIEhvd2V2ZXIsIGFzIHdlIGhhdmUgbWFueSBleHRyZW1lIGNhc2VzLCBpLmUuLCBvdXRsaWVycywgd2UgYXJlIGdvbm5hIHJlbW92ZSB0aGVtIGJlZm9yZSBwbG90dGluZyB0aGUgc3RhdGlzdGljcwoKYGBge3J9CgpxMSA8LSBxdWFudGlsZShtb2RpcyRmcnAsIC4yNSkKcTMgPC0gcXVhbnRpbGUobW9kaXMkZnJwLCAuNzUpCmlxciA8LSBJUVIobW9kaXMkZnJwKQoKbWlsZF9sb3cgPC0gcTEgLSAxLjUgKiBpcXIKbWlsZF9oaWdoIDwtIHEzICsgMS41ICogaXFyCgpjbGVhbl9tb2RpcyA8LSBtb2Rpc1ttb2RpcyRmcnAgPiBtaWxkX2xvdyAmIG1vZGlzJGZycCA8IG1pbGRfaGlnaCwgXSAjcm93cwoKbWVhbl9mcnBfbmFzYSA8LSBjbGVhbl9tb2RpcyAlPiUKICBtdXRhdGUoYWNxX3llYXIgPSB5ZWFyKGFjcV9kYXRlKSwKICAgICAgICAgYWNxX3dlZWsgPSB3ZWVrKGFjcV9kYXRlKSkgJT4lIAogIHNlbGVjdChhY3FfeWVhciwgYWNxX3dlZWssIGZycCkgJT4lIAogIGdyb3VwX2J5KGFjcV95ZWFyLCBhY3Ffd2VlaykgJT4lIAogIHN1bW1hcmlzZShtZWFuX2ZycCA9IG1lYW4oZnJwKSkKYGBgCgpgYGB7cn0Kc3BsaXR0ZWQgPC0gbWVhbl9mcnBfbmFzYSAlPiUgc2VsZWN0KGFjcV95ZWFyLCBhY3Ffd2VlaywgbWVhbl9mcnApCgojIFVzaW5nIGBkb2AgZnVuY3Rpb24gdG8gcmVwbGFjZSBOQXMgdmFsdWVzIHdpdGggdGhlIGxhc3QgcmVjb3JkcyB2YWx1ZQp0aWR5IDwtIHNwbGl0dGVkICU+JSBzcHJlYWQoa2V5ID0gYWNxX3llYXIsIHZhbHVlID0gbWVhbl9mcnApICU+JSBkbyh6b286Om5hLmxvY2YoLikpCnRpZHkkYDIwMTlgWzQwOm5yb3codGlkeSldIDwtIE5BCnRpZHkgPC0gdGlkeSAlPiUgCiAgZ2F0aGVyKCIyMDE1IiwgIjIwMTYiLCAiMjAxNyIsICIyMDE4IiwgIjIwMTkiLCBrZXkgPSAiYWNxX3llYXIiLCAidmFsdWUiID0gbWVhbl9mcnApCmBgYAoKYGBge3J9CnRpZHkgJT4lIAogIGdncGxvdChhZXMoeCA9IGFjcV93ZWVrLCB5ID0gbWVhbl9mcnAsIGNvbCA9IGFjcV95ZWFyKSkgKwogIGdlb21fbGluZSgpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiZ3JleSIsICJncmV5IiwgImdyZXkiLCAiZ3JleSIsICJyZWQiKSkgKwogIHNjYWxlX3hfY29udGludW91cygiV2VlayBvZiB0aGUgeWVhciIsIGJyZWFrcyA9IHNlcShmcm9tID0gMCwgdG8gPSA1MiwgYnkgPSA0KSkgKwogIHNjYWxlX3lfY29udGludW91cygiRmlyZSBSYWRpYXRpdmUgcG93ZXIiKQpgYGAKCmBgYHtyfQpjbGVhbl9tb2RpcyAlPiUgCiAgZ3JvdXBfYnkoYWNxX2RhdGUpICU+JSAKICBzdW1tYXJpc2UobWVhbl9mcnAgPSBtZWFuKGZycCkpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBhY3FfZGF0ZSwgeSA9IG1lYW5fZnJwKSkgKwogIGdlb21fbGluZSgpICsKICBzY2FsZV94X2RhdGUoZGF0ZV9icmVha3MgPSAiNCBtb250aHMiLCBkYXRlX2xhYmVscyA9ICIlYi8leSIpCmBgYAoKdGhpcyBncmFwaCBzaG93cyB0aGF0IHRoZXJlIDlzIGEgc3Ryb25nIHNlYXNvbmFsaXR5IGluIHRoZSBtZWFuIG9mIHRoZSBmaXJlIHJhZGlhdGl2ZSBwb3dlciB3aGljaCBoYXMgc3Ryb25ncyBjb21wb25lbnRzIG9mIHBlcmlvZHMgVHMgPSAzNjAgYW5kIFRzID0gMTgwIChUcyA9IHNhbXBsaW5nIHBlcmlvZCkuCgpMZXQncyBpbnZlc3RpZ2F0ZSB0aGUgZmlyZXMgb2YgdGhlIEFtYXpvbmlhIGR1cmluZyB0aGUgZmlyZSBzZWFzb246CgpDdW11bGF0aXZlIGFjdGl2ZSBmaXJlIGRldGVjdGlvbnMgZnJvbSBNYXkgMXN0IHRocm91Z2ggT2N0b2JlciAxc3QgZnJvbSBNT0RJUyAoQXF1YSArIFRlcnJhKSBhbmQgVklJUlMgKFNOUFApIHNob3cgdGhhdCBmaXJlIGRldGVjdGlvbnMgaW4gMjAxOSBoYXZlIGZhbGxlbiBiZWxvdyBjdW11bGF0aXZlIGxldmVscyBvZiBmaXJlIGFjdGl2aXR5IGRldGVjdGVkIGluIDIwMTIgKHRoZSBzdGFydCBvZiB0aGUgVklJUlMgcmVjb3JkKSBhbmQgMjAxNyBhY3Jvc3MgdGhlIExlZ2FsIEFtYXpvbi4gVGhyb3VnaCB0aGUgZW5kIG9mIFNlcHRlbWJlciwgZmlyZXMgaW4gMjAxOSB3ZXJlIG1vcmUgaW50ZW5zZSB0aGFuIGFueSB5ZWFyIHNpbmNlIDIwMTIsIG1lYXN1cmVkIGluIHRlcm1zIG9mIGZpcmUgcmFkaWF0aXZlIHBvd2VyLCBjb25zaXN0ZW50IHdpdGggdGhlIG9ic2VydmVkIGluY3JlYXNlIGluIGRlZm9yZXN0YXRpb24gdGhpcyB5ZWFyLgoKYGBge3J9CnNoYXBlIDwtIHJlYWRfc2YoZHNuID0gIi4vZ2VvX2RhdGEvbGVnYWxfYW1hem9uX3NpbXBsZSIsIGxheWVyID0gIlVGX0FNTGVnX0xMd2dzODRfU2ltcGxlIikKCiMgU2hhcGVmaWxlIG9mIGFtYXpvbiBsZWdhbCBhcmVhIGNhbiBhbHNvIGJlIG9idGFpbmVkIGF0IGh0dHA6Ly93d3cuZHBpLmlucGUuYnIvQW1iZGF0YS91bmlkYWRlc19hZG1pbmlzdHJhdGl2YXMucGhwCgpzaGFwZUlOUEUgPC0gcmVhZF9zZihkc24gPSAiLi9nZW9fZGF0YS9BbUxlZ19MTHdnczg0IiwgbGF5ZXIgPSAiYW1hemxlZ2FsIikKYGBgCgpgYGB7cn0KbGVnYWxfYW1hem9uIDwtIGFzLmRhdGEuZnJhbWUoc2hhcGUkZ2VvbWV0cnlbWzFdXVtbMV1dKQpuYW1lcyhsZWdhbF9hbWF6b24pIDwtIGMoImxvbmdpdHVkZSIsICJsYXRpdHVkZSIpCgpsZWdhbF9hbWF6b25fSU5QRSA8LSBhcy5kYXRhLmZyYW1lKHNoYXBlSU5QRSRnZW9tZXRyeVtbMV1dW1sxXV1bWzFdXSkKbmFtZXMobGVnYWxfYW1hem9uX0lOUEUpIDwtIGMoImxvbmdpdHVkZSIsICJsYXRpdHVkZSIpCgpsZWdhbF9hbWF6b24gJT4lIGdncGxvdChhZXMoeCA9IGxvbmdpdHVkZSwgeSA9IGxhdGl0dWRlKSkgKwogIGdlb21fcG9seWdvbigpCgpsZWdhbF9hbWF6b25fSU5QRSAlPiUgZ2dwbG90KGFlcyh4ID0gbG9uZ2l0dWRlLCB5ID0gbGF0aXR1ZGUpKSArCiAgZ2VvbV9wb2x5Z29uKCkKCiMgVG8gc2VlIGlmIGEgcG9pbnQgaXMgaW5zaWRlIGEgcG9seWdvbgojIHBvaW50LmluLnBvbHlnb24oLTYwLCAtNSwgc2hhcGUkZ2VvbWV0cnlbWzFdXVtbMV1dWywxXSwgc2hhcGUkZ2VvbWV0cnlbWzFdXVtbMV1dWywyXSkKYGBgCgoKYGBge3J9CmRmICU+JSAKICBzZWxlY3QoZXN0YWRvKSAlPiUgCiAgZ3JvdXBfYnkoZXN0YWRvKSAlPiUgCiAgc3VtbWFyaXNlKG4gPSBuKCkpICU+JSAKICByaWdodF9qb2luKG1hcF9kZiwgYnkgPSAnZXN0YWRvJykgJT4lIAogIGdncGxvdChhZXMoeCA9IGxvbmdpdHVkZSwgeSA9IGxhdGl0dWRlLCBncm91cCA9IGNvZGlnbykpICsgCiAgICBnZW9tX3BvbHlnb24oKSArIAogICAgZ2VvbV9wb2ludChpbmhlcml0LmFlcyA9IEYsIGRhdGEgPSBkYXRhMTksIGFlcyh4ID0gbG9uZ2l0dWRlLCB5ID0gbGF0aXR1ZGUsIGNvbCA9IGJpb21hKSwgc2l6ZSA9IDAuMSwgc2hhcGUgPSAzKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY2JwMSkgKwogICAgZ2VvbV9wYXRoKGNvbG9yID0gJ3doaXRlJywgc2l6ZSA9IDAuMSkgKwogIGdlb21fcGF0aChpbmhlcml0LmFlcyA9IEYsIGRhdGEgPSBsZWdhbF9hbWF6b25fSU5QRSwgbWFwcGluZyA9IGFlcyh4ID0gbG9uZ2l0dWRlLCB5ID0gbGF0aXR1ZGUpLCBjb2xvciA9ICJ5ZWxsb3ciKQpgYGAKCgpgYGB7cn0KbW9kaXNfZmNvdW50IDwtIHJlYWQuY3N2KCIuL2RhdGFiYXNlL2xlZ2FsX2FtYXpvbl9mY19mcnBfMjAxOTEwMDEvVGFibGVfTU9ESVNfZmlyZV9jb3VudHNfMjAwM18yMDE5LmNzdiIpCmBgYAoKYGBge3J9CnRpZHlfbW9kaXNfZmNvdW50IDwtIG1vZGlzX2Zjb3VudCAlPiUgCiAgZ2F0aGVyKC1gRE9ZYCwga2V5ID0gInllYXIiLCAidmFsdWUiID0gZmlyZXMpCgp0aWR5X21vZGlzX2Zjb3VudCR5ZWFyIDwtIGFzLmludGVnZXIoc3Vic3RyKHRpZHlfbW9kaXNfZmNvdW50JHllYXIsIDIsIDUpKQp0aWR5X21vZGlzX2Zjb3VudCRmaXJlcyA8LSBhcy5pbnRlZ2VyKHRpZHlfbW9kaXNfZmNvdW50JGZpcmVzKQoKYGBgCgpgYGB7cn0KZ2dwbG90bHkodGlkeV9tb2Rpc19mY291bnQgJT4lIAogIGdncGxvdChhZXMoeCA9IERPWSwgeSA9IGZpcmVzLCBjb2xvciA9IGZhY3Rvcih5ZWFyKSkpICsKICBnZW9tX2xpbmUoKSkKYGBgCgpgYGB7cn0KbW9kaXNfYXZnX2ZycCA8LSByZWFkLmNzdigiLi9kYXRhYmFzZS9sZWdhbF9hbWF6b25fZmNfZnJwXzIwMTkxMDAxL1RhYmxlX01PRElTX2ZpcmVfcmFkaWF0aXZlX3Bvd2VyXzIwMDNfMjAxOS5jc3YiKQpgYGAKCmBgYHtyfQp0aWR5X21vZGlzX2F2Z19mcnAgPC0gbW9kaXNfYXZnX2ZycCAlPiUgCiAgZ2F0aGVyKC1gRE9ZYCwga2V5ID0gInllYXIiLCAidmFsdWUiID0gZmlyZXMpCgp0aWR5X21vZGlzX2F2Z19mcnAkeWVhciA8LSBhcy5pbnRlZ2VyKHN1YnN0cih0aWR5X21vZGlzX2F2Z19mcnAkeWVhciwgMiwgNSkpCnRpZHlfbW9kaXNfYXZnX2ZycCRmaXJlcyA8LSBhcy5pbnRlZ2VyKHRpZHlfbW9kaXNfYXZnX2ZycCRmaXJlcykKYGBgCgpgYGB7cn0KZ2dwbG90bHkoCiAgdGlkeV9tb2Rpc19hdmdfZnJwICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBET1ksIHkgPSBmaXJlcywgY29sb3IgPSBmYWN0b3IoeWVhcikpKSArCiAgZ2VvbV9saW5lKCkKKQpgYGAKCgoKRnJvbSBOYXNhUG93ZXIgQVBJIHdlIGNhbiBvYnRhaW4gdXNlZnVsIGRhdGEgZm9yIGFib3V0IDE0NiB3ZWF0aGVyIGFuZCBjbGltYXRlIHBhcmFtZXRlcnMsIHN1Y2ggYXM6CgpSZWxhdGl2ZSBodW1pZHR5IChhdCB0d28gbWV0ZXJzKQpUZW1wZXJhdHVyZSAoYXQgdHdvIG1ldGVycykKUHJlY2lwaXRhdGlvbiAobW0pCk1heGltdW0vTWluaW11bSBNb250aGx5IERpZmZlcmVuY2UgRnJvbSBNb250aGx5IEF2ZXJhZ2VkIEFsbCBTa3kgSW5zb2xhdGlvbgpXaW5kIFNwZWVkIAoKZ2VvZ3JhcGhpY2FsIGRhdGEgYXJlIHByb3ZpZGVkIGF0IHRoZSByZXNvbHV0aW9uIG9mIDEvMiBhcmMgZGVncmVlIGxvbmdpdHVkZSBieSAxLzIgYXJjIGRlZ3JlZSBsYXRpdHVkZS4gZm9yIG1vcmUgZGV0YWlsZWQgaW5mbyBnbyB0byBodHRwczovL3Bvd2VyLmxhcmMubmFzYS5nb3YvZG9jdW1lbnRzL1BPV0VSX0RhdGFfdjlfbWV0aG9kb2xvZ3kucGRmCgpBbm90aGVyIHVzZWZ1bCByZXNvdXJjZSBjYW4gYmUgZm91bmQgYXQgaHR0cHM6Ly9lYXJ0aG9ic2VydmF0b3J5Lm5hc2EuZ292L2ltYWdlcy8xNDU0NjQvZmlyZXMtaW4tYnJhemlsCgpBbHNvIGluIGh0dHBzOi8vd3d3Lmdsb2JhbGZpcmVkYXRhLm9yZy9kYXRhLmh0bWwgd2UgY2FuIGZpbmQgZGF0YSBzdWNoIGFzIGNhcmJvbiBlbWlzc2lvbnMgYW5kIGRyeSBtYXR0ZXIgZW1pc3Npb25zLgoKRm9yIGhpZ2hseSBwZXJzb25hbGl6YWJsZSBpbWFnZXMgZ28gdG8gaHR0cHM6Ly93b3JsZHZpZXcuZWFydGhkYXRhLm5hc2EuZ292LwoKRGV0YWlsZWQgaW5mb3JtYXRpb24gYWJvdXQgZmlyZXMgb24gdGhlIExlZ2FsIEFtYXpvbiBhcmVhIGlzIGdpdmVuIGF0IGh0dHA6Ly93d3cuZ2xvYmFsZmlyZWRhdGEub3JnL2ZvcmVjYXN0Lmh0bWwjYW1hem9uYXMKClRob3VnaHRzIG9uIGZpcmUgZm9yZWNhc3RpbmcgaHR0cHM6Ly93d3cubmFzYS5nb3YvZmVhdHVyZS9nb2RkYXJkLzIwMTkvZmlyZS1mb3JlY2FzdGluZy1mcm9tLXNtYXJ0LXBob25lLWluLXdpbGRlcm5lc3MKCldpbGRmaXJlcyBhZ2FpbnN0IGJpb2RpdmVyc2l0eSBodHRwczovL29ubGluZWxpYnJhcnkud2lsZXkuY29tL2RvaS9hYnMvMTAuMTExMS9idHAuMTIyNjcgYW5kCmh0dHBzOi8vbGluay5zcHJpbmdlci5jb20vYXJ0aWNsZS8xMC4xMDA3L3MxMDUzMS0wMTItMDQyNi04CgoKCgo=